커머스 관련 개발을 하다보니 수많은 Enum 들을 만나게 된다. 아래 Enum 은 간단한 상품타입 코드다. 단순 옵션과 복잡한 옵션 두개의 타입이 있다.
public enum ProductType {
SIMPLE_OPTION,
COMPLEX_OPTION
}
상품타입에 따라 달라지는 부분을 테스트 하기 위해선 ParameterizedTest 와 EnumSource 를 사용하면 된다.
@ParameterizedTest
@EnumSource(names = {"SIMPLE_OPTION", "COMPLEX_OPTION"})
void enumSourceTest(ProductType productType) {
System.out.println(productType);
}
하지만 Enum 들 관계에 따라 비지니스 로직이 분기처리되는 경우는 매우 흔하고 그부분을 테스트하고 싶다. 아래 코드는 상품레벨의 상품타입과 그 하위인 아이템레벨의 아이템타입 관계를 표현했다. ProdcutType 과 ItemType 조합의 모든 경우의 수는 8가지지만, 실질적으로 가능한 조합은 4가지다.
@Value
@Builder
public class Product {
ProductType productType;
List<Item> items;
@Value
@Builder
public static class Item {
ItemType itemType;
}
}
// ProductType 과 ItemType 의 관계
// SIMPLE_OPTION - SIMPLE
// COMPLEX_OPTION - COMBINATION1
// COMPLEX_OPTION - COMBINATION2
// COMPLEX_OPTION - COMBINATION3
public enum ProductType {
SIMPLE_OPTION,
COMPLEX_OPTION
}
public enum ItemType {
SIMPLE,
COMBINATION1,
COMBINATION2,
COMBINATION3,
}
그래서 위 4가지 조합을 따로 셋팅해줘야 하는데 ParameterizedTest 와 MethodSource 를 활용할 수 있다.
@ParameterizedTest
@MethodSource("productTypeAndItemTypeSet")
void methodSourceTest(ProductType productType, ItemType itemType) {
System.out.println(productType + " : " + itemType);
}
private static Stream productTypeAndItemTypeSet() {
return Stream.of(
Arguments.of(
ProductType.SIMPLE_OPTION,
ItemType.SIMPLE
),
Arguments.of(
ProductType.COMPLEX_OPTION,
ItemType.COMBINATION1
),
Arguments.of(
ProductType.COMPLEX_OPTION,
ItemType.COMBINATION2
),
Arguments.of(
ProductType.COMPLEX_OPTION,
ItemType.COMBINATION3
)
);
}
org.junit.jupiter.api.DynamicTest 와 TestFactory 를 활용하는 방법도 있다. 코드를 먼저 보자. Stream.of 로 4가지 Enum 조합을 셋팅해주고 flatMap 에서 각각 DynamicTest.dynamicTest 를 돌리는 구조다.
@TestFactory // @Test 가 아니라 @TestFactory 다
Stream<DynamicTest> dynamicTestTest() {
return Stream.of(
Map.of(ProductType.SIMPLE_OPTION, ItemType.SIMPLE),
Map.of(ProductType.COMPLEX_OPTION, ItemType.COMBINATION1),
Map.of(ProductType.COMPLEX_OPTION, ItemType.COMBINATION2),
Map.of(ProductType.COMPLEX_OPTION, ItemType.COMBINATION3)
)
.flatMap(testCaseMap ->
testCaseMap.entrySet().stream()
.map(it ->
DynamicTest.dynamicTest(testCaseMap.toString(), () -> {
ProductType productType = it.getKey();
ItemType itemType = it.getValue();
System.out.println(productType + " : " + itemType);
}
)
)
);
}
}
자바는 기본적으로 Pair 클래스를 제공하지 않아서 Map 을 썼더니 flatMap 을 써야하는 등 코드가 좀 복잡하게 구현됐다.
코틀린 버전으로 그리고 Pair 를 써서 만들면 더 심플하긴 하다.
@TestFactory
fun dynamicTestTest(): Stream<DynamicTest> {
return Stream.of(
Pair(ProductType.SIMPLE_OPTION, ItemType.SIMPLE),
Pair(ProductType.COMPLEX_OPTION, ItemType.COMBINATION1),
Pair(ProductType.COMPLEX_OPTION, ItemType.COMBINATION2),
Pair(ProductType.COMPLEX_OPTION, ItemType.COMBINATION3),
)
.map { pair ->
DynamicTest.dynamicTest(pair.toString()) {
println("${pair.first} : ${pair.second}")
}
}
}
cf) 자바에서 기본적으로 제공은 안하지만 스프링에서 제공해주는 org.springframework.data.util.Pair 를 사용할 수 있다.
'Java' 카테고리의 다른 글
돈(Money) 타입 (0) | 2023.04.29 |
---|---|
java stream 으로 Map 다루는 방법 (0) | 2023.04.06 |
자바로 같은 상품 Grouping (0) | 2023.02.05 |
index 가 필요해도 자바 고전 for 문 안쓰는 방법 (0) | 2023.01.14 |
자바 Function.andThen 과 apply 작동 순서 (0) | 2022.08.30 |