앞날 창창보
article thumbnail
Published 2024. 4. 16. 12:25
Fixture Monkey를 써야 할까? 기술고민

Fixture 랜덤 박스!

테스트 코드를 작성하다보면, Fixture를 어떻게 만들지 고민할 때가 많다고 느껴진다. 크게는 모듈을 분리하는 것부터, 작게는 메서드 안에서 직접 객체를 생성하는 거 까지 할 수 있는 방법이 너무 많다. 그리고 Fixture Monkey와 같은 랜덤 데이터로 객체를 생성해주는 라이브러리가 있다.

 

이번 글에서는 Fixtiure Monkey라는 네이버에서 지원하는 라이브러리를 쓸지 말지에 대해서 이야기 해보도록 하겠다.

Fixture Monkey가 뭘까?


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

Fixture Monkey를 한줄로 정리하면, 제어가능한 임의의 테스트 객체를 생성하는 가장 쉬운 방법이다.

 

Fixture Monkey 기능

1. 간편하게 랜덤하고 복잡한 제약조건을 가지는 객체 생성

Jqwik기반으로 JSR-303, JSR-380 annotation에 따라 자동으로 속성을 생성

테스트 코드에서도 속성 조건을 생성할 수 있다.

 

2. 설정한 제약조건 검증

bean validator 2.0 표준을 지키는 validator를 추가하면 자동으로 등록해서 fixture 값에 대한 검증을 진행한다.

기본적으로 검증을 통과한 객체만 생성한다.

 

3. 테스트 케이스마다 다르게 객체 제어

실패 테스트를 작성해야할 때는 검증에 맞지 않는 값을 추가해야할 때가 있다.

AritraryBuilder에서 아래와 같이 임의의 객체를 빌더 형식으로 만들 수 있다.

 

https://tv.naver.com/v/23650158

 

 

 

 

Fixture Monkey는 어떻게 사용해야할까?


1. gradle에 의존성을 추가

testImplementation("com.navercorp.fixturemonkey:fixture-monkey-starter:1.0.14")

 

2. 테스트 객체 생성하기

lombok.anyConstructor.addConstructorProperties=true 가 lombok.config 파일에 추가되어 있어야 합니다.

 

- FixtureMonkey 객체 생성하기

void 함수() {
	FixtureMonkey fixtureMonkey = FixtureMonkey.builder()
        .objectIntrospector(ConstructorPropertiesArbitraryIntrospector.INSTANCE)
        .build();
}

혹은

private static final FixtureMonkey fixtureMonkey = FixtureMonkey.builder()
        .objectIntrospector(ConstructorPropertiesArbitraryIntrospector.INSTANCE)
        .build();

 

- FixtureMonkey 객체 사용하기

// 하나의 Fixture가 필요할 때
{Fixture를 생성할 클래스} actual = fixtureMonkey.giveMeOne({Fixture를 생성할 클래스}.class);

// 여러개의 Fixture가 필요할 때 stream 혹은 List로 가져올 수 있음
Stream<{Fixture를 생성할 클래스}> productStream = fixtureMonkey.giveMe({Fixture를 생성할 클래스}.class);
List<{Fixture를 생성할 클래스}> productList = fixtureMonkey.giveMe({Fixture를 생성할 클래스}.class, 3);

왜 스트림으로 가져올 때는 개수를 전달안하는 지 모르겠다.

 

3. 빈의 유효성 검사 추가하기

빈의 유효성 검사 추가하기가 무슨 말이냐면, jakarta or javax .validation.contraints 의 제약 어노테이션을 지원한다는 말이다.

 

예를 들어서,

...
import jakarta.validation.constraints.Min;

public class Object {
    @Min(1000)
    pirvate Integer a;
    ...
}

다음과 같은 클래스의 fixture를 생성하고자한다면, a의 값은 무조건 1000아래로만 들어가게 하는 것이다.

 

fixture-monkey-starter 종속성을 추가했으면, 이미 포함되어 있을 것이고, 아니면 아래의 내용을 gradle에 추가하면 된다.

testImplementation("com.navercorp.fixturemonkey:fixture-monkey-jakarta-validation:1.0.14")

 

설정하는 방법은

FixtureMonkey fixtureMonkey = FixtureMonkey.builder()
    .plugin(new JakartaValidationPlugin()) // or new JavaxValidationPlugin()
    .build();

다음과 같이 fixtureMonkey 객체를 생성하면 된다.

 

4. 사용자 정의 객체 생성하기

특정 테스트에 적합하게 테스트 픽스처를 조정해야할 수 있다.

 

예를 들면

@Value
public class Product {
    long id;

    String productName;

    long price;

    List<String> options;

    Instant createdAt;
}

다음의 객체에서 id가 무조건 1000인 인스턴스가 필요할 수 있다. 그런 경우엔 giveMeBuilder 메서드를 사용하여 Fixture Monkey에서 타입 빌더를 가져올 수 있다. 빌더를 사용해서 픽스처를 사용자 정의 할 수 있다.

 

FixtureMonkey fixtureMonkey = FixtureMonkey.builder()
    .objectIntrospector(ConstructorPropertiesArbitraryIntrospector.INSTANCE)
    .build();
long id = 1000;

Product actual = fixtureMonkey.giveMeBuilder(Product.class)
    .set("id", id)
    .sample();

다음과 같이 작성하면 id가 무조건 1000인 인스턴스를 가져올 수 있다.

 

다음과 같이 코드를 작성하다보면 giveMe를 했을 때 계속 null이 올수도 있다. (내가 그랬다.) 다음의 이유는

.objectIntrospector(ConstructorPropertiesArbitraryIntrospector.INSTANCE)

 FixtureMonkey 객체를 생성할 때 사용하는 이 한줄 때문인데, 데이터 생성 전략을 선택하는 줄이다. 데이터 생성 전략에는 총  5개가 있는데, 간략히 설명하자면, 기본 생성자와 세터가 필요한 것(기본 값), 리플렉션으로 필드 전체에 접근해서 데이터를 생성하는 것, 생성자로 하는 것(위의 코드에 있는 것), 빌더가 있어야 하는 것이 있는데, 상세한 것은 이 글에서 확인해보도록 하자.

 

일단 위에서 사용한 생성자로 값을 채워주는 것으로는 나는 @Entity를 붙인 클래스에서 null이 계속 왔다. 기본 생성자 때문이라고 느껴졌다. (확실하진 않다.) 어짜피 거의 모든 곳에서 엔티티를 Fixture로 사용할 것이기 때문에 기본생성자가 있어야하는 리플렉션으로 접근하는 

.objectIntrospector(FieldReflectionArbitraryIntrospector.INSTANCE)

이것을 사용하기로 했다.

 

Fixture Monkey를 사용해야할까?


fixture monkey의 개념과 사용 방법을 알아보니, fixture monkey는 거의 모든 상황에서 사용되도 좋을 것 같다는 생각이 든다.

 

1. fixture 코드가 훨씬 줄어들고,

2. 임의의 값으로, 엣지케이스를 쉽게 잡아준다.

3. 복잡한 구조의 객체도 쉽게 생성할 수 있다.

4. 성능 문제 없다.

 

그렇다면 정말 why not 인 것 같다.

 

테스트 코드를 작성해야하고, test fixture를 작성하는 비용이 Fixture Monkey를 설정하고 학습하는 비용보다 크다고 느껴진다면, 주저하지말고 도입하기를 권장한다.

 
 
 
 
 
 

검색 태그