[TIL] FixtureMonkey - 랜덤 데이터 생성 라이브러리

phdljr·2023년 12월 6일
2

TIL

목록 보기
42/70

테스트를 진행하던 도중, 엔티티 더미 데이터를 생성할 필요가 생겼다.
그러나, 이를 생성하는것도 일이었다.

그러던 도중, 데이터 생성에 도움을 주는 FixtureMonkey를 알게 되었고, 간단하게 사용해보는 시간을 가져보았다.

예시 코드를 통해 사용하는 방법을 간접적으로 소개해보는 시간을 가져본다.


FixtureMonkey

https://naver.github.io/fixture-monkey/

  • 테스트용 랜덤 데이터 생성기
@Test
void test() {
  // given
  FixtureMonkey fixtureMonkey = FixtureMonkey.create();

  // when
  Animal actual = fixtureMonkey.giveMeOne(Animal.class);

  // then
  System.out.println(actual);
}

데이터 생성 전략

  • 데이터 생성 전략에는 다음과 같은 전략이 존재
    • BeanArbitraryIntrospector
      • 기본 전략
      • 기본 생성자와 setter 필수
    • FieldReflectionArbitraryIntrospector
      • 리플랙션을 통해 필드에 직접 접근해서 데이터 생성
      • 기본 생성자 필수
    • ConstructorPropertiesArbitraryIntrospector
      • 하나 이상의 생성자 필수
      • 적용할 생성자에 @ConstructorProperties 어노테이션을 달아줘야 함
      • 또는 해당 클래스가 record면 됨
      • 또는 롬복을 사용한다면, lombok.config 파일에 lombok.anyConstructor.addConstructorProperties=true 을 설정해주면 됨
    • BuilderArbitraryIntrospector
      • 해당 클래스의 빌더로 생성
      • 빌더 클래스가 있어야 함
      • 롬복의 @Builder 를 통해 생성 가능
    • FailoverArbitraryIntrospector
      • 여러 개의 전략을 우선 순위별로 설정
      • 다양한 클래스 데이터를 만들 때 용이

예시 코드

  • 기본 전략을 사용하려면, setter와 기본 생성자가 필요
    @Test
    void test() {
      // given
      FixtureMonkey fixtureMonkey = FixtureMonkey.create();
    
      // when
      Animal actual = fixtureMonkey.giveMeOne(Animal.class);
    
      // then
      System.out.println(actual);
    }
  • 기본 타입은 별도의 설정 필요 없음
    // 임의 Integer 생성
    Integer number = FixtureMonkey.create().giveMeOne(Integer.class);
    
    // 100 이상 임의 Integer 생성
    Integer number2 = FixtureMonkey.create().giveMeBuilder(Integer.class)
        .set(Arbitraries.integers().greaterOrEqual(100)).sample();
  • setter나 기본 생성자가 없다면, 다른 전략으로 데이터 생성 가능
    FixtureMonkey fixtureMonkey = FixtureMonkey.builder()
            .objectIntrospector(FieldReflectionArbitraryIntrospector.INSTANCE)
            .build();
    
    // 임의 객체 생성
    List<Sample> sample = fixtureMonkey.giveMe(Sample.class, 100);
    sample.forEach(System.out::println);
    System.out.println("===============================");
    
    // 임의 객체 생성
    List<Sample> sample2 = fixtureMonkey.giveMeBuilder(Sample.class)
        .set("age", Arbitraries.integers().between(1, 100))
        .set("title", Arbitraries.strings().ofLength(10).alpha())
        .sampleList(10);
    sample2.forEach(System.out::println);
    
    Sample actual = fixtureMonkey.giveMeBuilder(Sample.class)
        .set("age", 1000)
        .set("title", "Book")
        .sample();
    System.out.println(sample);
    
    // 한글 설정
    List<Sample> sample3 = fixtureMonkey.giveMeBuilder(Sample.class)
        .set("age", Arbitraries.integers().between(1, 100))
        .set("title", Arbitraries.strings().ofLength(10).withCharRange((char) 0xAC00,
            (char) 0xD7A3))
        .sampleList(10);
    sample3.forEach(System.out::println);
    
    // 배열에 들어간 값만 랜덤으로 배정
    char[] chars = {'가', '나', '다', '라', '마'};
    
    List<Sample> sample4 = fixtureMonkey.giveMeBuilder(Sample.class)
        .set("age", Arbitraries.integers().between(1, 100))
        .set("title", Arbitraries.strings().ofLength(10).withChars(chars))
        .sampleList(10);
    sample4.forEach(System.out::println);
  • 연관관계 맵핑 데이터 생성
    @BeforeEach
    public void setup(){
        fixtureMonkey = FixtureMonkey.builder()
            .plugin(new JakartaValidationPlugin())
            .objectIntrospector(FieldReflectionArbitraryIntrospector.INSTANCE)
            .build();
    }
    
    @Test
    public void relationalTest(){
        List<User> users = fixtureMonkey.giveMeBuilder(User.class)
            .setNotNull("*")
            .set("password", Arbitraries.strings().withCharRange('a', 'z').ofLength(10))
            .sampleList(1000);
        userRepository.saveAll(users);
    
        List<Card> cards = fixtureMonkey.giveMeBuilder(Card.class)
            .setNotNull("*")
            .setNull("comments")
            .set("user", Arbitraries.of(users))
            .sampleList(30);
        cardRepository.saveAll(cards);
    
        cards.forEach(System.out::println);
    }

스프링 부트 환경에서 테스트할 시 주의사항

  • gradle 환경에서 dependency를 추가할 시, 무조건 testImplementation으로 추가해두기

참조

profile
난 Java도 좋고, 다른 것들도 좋아

0개의 댓글