사용자 정의 객체 생성하기
Fixture Monkey를 사용하면 테스트 요구사항에 맞게 테스트 객체를 커스터마이즈할 수 있습니다. 실제 예제를 통해 살펴보겠습니다.
왜 테스트 객체를 커스터마이즈해야 할까요?
예를 들어, 1000원 이상인 상품에만 10% 할인을 적용하는 서비스를 테스트한다고 가정해봅시다. 두 가지 시나리오를 테스트해야 합니다:
- 할인이 적용되어야 하는 상품 (가격 > 1000원)
- 할인이 적용되지 않아야 하는 상품 (가격 ≤ 1000원)
Fixture Monkey를 사용하지 않는다면 다음과 같이 코드를 작성해야 합니다:
// Fixture Monkey 없이
Product expensiveProduct = new Product(1, "고가 상품", 2000, ...);
Product cheapProduct = new Product(2, "저가 상품", 500, ...);
Fixture Monkey를 사용하면 이러한 테스트 객체를 더 쉽고 유연하게 생성할 수 있습니다.
단계별 가이드
먼저 간단한 Product 클래스를 살펴보겠습니다:
@Value
public class Product {
long id;
String productName;
long price;
List<String> options;
Instant createdAt;
}
1단계: FixtureMonkey 인스턴스 생성하기
먼저 적절한 introspector를 사용하여 FixtureMonkey 인스턴스를 생성합니다:
FixtureMonkey fixtureMonkey = FixtureMonkey.builder()
.objectIntrospector(ConstructorPropertiesArbitraryIntrospector.INSTANCE)
.build();
val fixtureMonkey = FixtureMonkey.builder()
.objectIntrospector(ConstructorPropertiesArbitraryIntrospector.INSTANCE)
.build()
2단계: 특정 가격을 가진 Product 생성하기
이제 할인 테스트를 위해 가격이 2000원인 상품을 생성해보겠습니다:
@Test
void testDiscountApplied() {
// given
Product expensiveProduct = fixtureMonkey.giveMeBuilder(Product.class)
.set("price", 2000L) // 가격을 2000으로 설정
.sample();
// when
double discount = discountService.calculateDiscount(expensiveProduct);
// then
then(discount).isEqualTo(200.0); // 2000의 10%
}
@Test
fun testDiscountApplied() {
// given
val expensiveProduct = fixtureMonkey.giveMeBuilder(Product::class.java)
.set("price", 2000L) // 가격을 2000으로 설정
.sample()
// when
val discount = discountService.calculateDiscount(expensiveProduct)
// then
then(discount).isEqualTo(200.0) // 2000의 10%
}
3단계: 커스터마이즈된 리스트를 가진 Product 생성하기
컬렉션도 커스터마이즈할 수 있습니다. 예를 들어, 특정 옵션을 가진 상품을 테스트하려면:
@Test
void testProductWithOptions() {
// given
Product actual = fixtureMonkey.giveMeBuilder(Product.class)
.size("options", 3) // 리스트 크기를 3으로 설정
.set("options[1]", "red") // 두 번째 요소를 "red"로 설정
.sample();
// then
then(actual.getOptions()).hasSize(3);
then(actual.getOptions().get(1)).isEqualTo("red");
}
@Test
fun testProductWithOptions() {
// given
val actual = fixtureMonkey.giveMeBuilder(Product::class.java)
.size("options", 3) // 리스트 크기를 3으로 설정
.set("options[1]", "red") // 두 번째 요소를 "red"로 설정
.sample()
// then
then(actual.options).hasSize(3)
then(actual.options[1]).isEqualTo("red")
}
생성된 Product는 다음과 같이 보일 것입니다:
Product(
id=42, // 임의의 값
productName="product-value-1", // 임의의 값
price=1000, // 임의의 값
options=["option1", "red", "option3"], // 커스터마이즈된 리스트
createdAt=2024-03-21T10:15:30Z // 임의의 값
)
주의사항과 팁
- 필드 이름
- 클래스에 정의된 필드 이름을 정확히 사용해야 합니다
- 잘못된 예:
set("product_name", "test")
(필드 이름 불일치) - 올바른 예:
set("productName", "test")
- 팁: IDE의 코드 완성 기능을 사용하여 필드 이름 오타를 방지하세요
- 팁: 타입 안전한 필드 접근을 위해
setExp
또는setExpGetter
를 사용하세요 - 팁: 향상된 코드 완성과 타입 안전성을 위해 Fixture Monkey Helper를 설치하세요
// 타입 안전한 필드 접근
.set(javaGetter(Product::getProductName), "test")
// 타입 안전한 필드 접근
.setExp(Product::productName, "test")
// 또는
.setExpGetter(Product::productName, { "test" })
컬렉션 인덱싱
- 리스트 인덱스는 0부터 시작한다는 것을 기억하세요
- 잘못된 예:
set("options[3]", "red")
(크기가 3인 리스트의 경우) - 올바른 예:
set("options[2]", "red")
- 팁: 특정 인덱스를 설정하기 전에
size()
를 사용하여 리스트 크기를 먼저 설정하세요
타입 안전성
- 값의 타입을 올바르게 사용해야 합니다
- 잘못된 예:
set("price", "1000")
(String 대신 Long 사용) - 올바른 예:
set("price", 1000L)
- 팁: IDE의 타입 힌트를 활용하여 올바른 값 타입을 사용하세요
Fixture Monkey 사용 전후 비교
Fixture Monkey 사용 전:
// 특정 옵션을 가진 상품 생성
List<String> options = new ArrayList<>();
options.add("option1");
options.add("red");
options.add("option3");
Product product = new Product(1, "테스트 상품", 1000, options, Instant.now());
Fixture Monkey 사용 후:
// 같은 결과를 더 적은 코드로 생성
Product product = fixtureMonkey.giveMeBuilder(Product.class)
.size("options", 3)
.set("options[1]", "red")
.sample();
프로퍼티 선택과 값 설정에 대한 더 많은 예제는 커스터마이징 섹션을 참고하세요.