6 min to read
Spring-Boot-Test Fixture Monkey 개요
Fixture Monkey 를 사용해 귀차니즘과 엣지 케이스를 잡아보자.
테스트 코드를 작성할 때 데이터를 표현하는 클래스들을 생성하기란 귀찮고 귀찮다. 필드가 조금만 많아져도 생성하기 귀찮고 필드가 없어도 귀찮다. ‘누가 자동으로 생성해주면 좋겠다’ 를 해결해주는 게 Fixture Monkey
이다. 무작위, 유효성 검사, 사용자 설정 등을 적용하여 인스턴스 생성이 가능하다.
준비
- github & 공식 문서
🔗naver-fixture-monkey-github
🔗naver-fixture-monkey-docs
- 의존성
testImplementation 'com.navercorp.fixturemonkey:fixture-monkey-starter:1.0.14'
Fixture Monkey 로 객체를 생성한다면?
예를 들어 아래와 같은 코드가 있다면, 생성하기 귀찮을 것이다. (빌더가 있다하더라도.)
@Value
public class Product {
long id;
String productName;
long price;
List<String> options;
Instant createdAt;
ProductType productType;
Map<Integer, String> merchantInfo;
}
만약 FixtureMonkey
를 사용한다면 //when
부분처럼 뿅하고 얻을 수 있다.
@Test
void test() {
// given
FixtureMonkey fixtureMonkey = FixtureMonkey
.builder()
.objectIntrospector(ConstructorPropertiesArbitraryIntrospector.INSTANCE)
.build();
// when
Product actual = fixtureMonkey.giveMeOne(Product.class);
// then
then(actual).isNotNull();
}
객체 생성 Introspector
FixtureMonkey
는 마법처럼 객체를 생성해주지만 진짜 마법은 아니다. 생성 방법을 정의할 수 있다. 인스턴스 생성 방법에 사용되는 여러 Introspector
들을 간단히 살펴본다.
BeanArbitraryIntrospector
객체 생성에 사용하는 기본 Introspector
. 리플렉션과 setter 메서드를 사용한다.
FixtureMonkey fixtureMonkey = FixtureMonkey
.builder()
.objectIntrospector(BeanArbitraryIntrospector.INSTANCE)
.build();
ConstructorPropertiesArbitraryIntrospector
주어진 생성자로 객체를 생성한다. @ConstructorProperties
가 있거나 없으면 클래스가 레코드 타입이어야한다. 레코드 클래스를 생성할 때 여러 생성자를 가질 경우 @ConstructorProperties
주석이 있는 생성자가 우선 선택된다.
FixtureMonkey fixtureMonkey = FixtureMonkey
.builder()
.objectIntrospector(ConstructorPropertiesArbitraryIntrospector.INSTANCE)
.build();
FieldReflectionArbitraryIntrospector
리플렉션을 사용해 생성한다. getter
or setter
가 필요하다.
FixtureMonkey fixtureMonkey = FixtureMonkey
.builder()
.objectIntrospector(FieldReflectionArbitraryIntrospector.INSTANCE)
.build();
BuilderArbitraryIntrospector
클래스 빌더를 사용해 생성한다.
FixtureMonkey fixtureMonkey = FixtureMonkey
.builder()
.objectIntrospector(BuilderArbitraryIntrospector.INSTANCE)
.build();
FailoverArbitraryIntrospector
여러 개의 Introspector
를 사용할 수 있다. 설정한 Introspector
중 하나가 생성에 실패하더라도 다음 Introspector
로 객체 생성을 시도한다.
FixtureMonkey monkey = FixtureMonkey.builder()
.objectIntrospector(new FailoverIntrospector(
List.of(
FieldReflectionArbitraryIntrospector.INSTANCE,
ConstructorPropertiesArbitraryIntrospector.INSTANCE,
BuilderArbitraryIntrospector.INSTANCE
)))
.build();
인스턴스 생성하기
.giveMeOne();
: 특정 타입의 인스턴스를 하나 얻을 수 있다.
Product actual = fixtureMonkey.giveMeOne(Product.class);
.giveMe();
: 특정한 타입으로 고정되고 두 개 이상의 인스턴스가 필요할 때 사용할 수 있다. 크기를 지정해 스트림, 리스트를 생성할 수 있다.
List<Product> productList = fixtureMonkey.giveMe(Product.class, 3);
List<List<String>> strListList = fixtureMonkey.giveMe(new TypeReference<List<String>>() {}, 3);
.giveMeBuilder();
: 인스턴스를 커스텀할 수 있다. ‘productName’ 필드를 ‘lkdcode’ 로 고정하고 그외에 필드는 랜덤으로 생성해준다.
Product actual = monkey.giveMeBuilder(clazz)
.set("productName", "lkdcode")
.sample();
With Validation
FixtureMonkey
는 무작위 값으로 생성해주기 때문에 의도와 다른 값이 항상 생성된다. jakarta.validation
으로 Bean 검사를 추가할 수 있다.
- 의존성 추가하기
testImplementation("com.navercorp.fixturemonkey:fixture-monkey-jakarta-validation:1.0.14")
FixtureMonkey
에JakartaValidationPlugin
을 추가해준다.
FixtureMonkey fixtureMonkey = FixtureMonkey.builder()
.plugin(new JakartaValidationPlugin()) // or new JavaxValidationPlugin()
.build();
위에서 봤던 Product
클래스에 유효성 검사 어노테이션을 추가한다.
@Value
public class Product {
@Min(1)
long id;
@NotBlank
String productName;
@Max(100000)
long price;
@Size(min = 3)
List<@NotBlank String> options;
@Past
Instant createdAt;
}
FixtureMonkey
가 인스턴스를 생성할 때 유효한 객체로 생성해준다.
Product actual = fixtureMonkey.giveMeOne(Product.class); // 유효성 검사 Ok
인스턴스 커스터마이징
FixtureMonkey
는 ArbitraryBuilder
를 통해 생성된 객체를 커스텀할 수 있다.
set()
setter 다. 키,벨류로 해당 필드의 값을 할당한다. 아래의 코드는 id 라는 필드의 값을 1000으로 할당해 생성한다.
fixtureMonkey.giveMeBuilder(Product.class).set("id", 1000);
Just
set()
을 사용할 때 Just
로 래핑하여 설정할 수 있다.
Product product = fixture.giveMeBuilder(Product.class)
.set("options", Values.just(List.of("red", "medium", "adult"))
.set("options[0]", "blue")
.sample();
size(), minSize(), maxSize()
특정 컬렉션의 사이즈를 설정할 수 있다. default 설정은 0~3이다.
fixtureMonkey.giveMeBuilder(Product.class)
.size("options", 5); // size:5
fixtureMonkey.giveMeBuilder(Product.class)
.size("options", 3, 5); // minSize:3, maxSize:5
fixtureMonkey.giveMeBuilder(Product.class)
.minSize("options", 3); // minSize
fixtureMonkey.giveMeBuilder(Product.class)
.maxSize("options", 5); // maxSize:5
setNull(), setNotNull()
속성을 Null
로 하거나 값이 존재하도록 보장할 수 있다.
fixtureMonkey.giveMeBuilder(Product.class)
.setNull("id");
fixtureMonkey.giveMeBuilder(Product.class)
.setNotNull("id");
공식문서를 참고한다면 이외에도 다양한 커스터마이징을 지원하는 것을 확인할 수 있다.
Comments