DEV Community

yangbongsoo
yangbongsoo

Posted on

Test based on Enum type(DynamicTest)

When developing e-commerce, one encounters numerous Enums. The following Enum represents a simple product type code. There are two types: simple options and complex options.

public enum ProductType {
    SIMPLE_OPTION,
    COMPLEX_OPTION
}
Enter fullscreen mode Exit fullscreen mode

To test the parts that vary according to the product type, we can use @ParameterizedTest and @EnumSource.

@ParameterizedTest
@EnumSource(names = {"SIMPLE_OPTION", "COMPLEX_OPTION"})
void enumSourceTest(ProductType productType) {
    System.out.println(productType);
}
Enter fullscreen mode Exit fullscreen mode

Image description

However, it's very common for business logic to branch based on the relationships between Enums, and one may want to test those parts.

The code below represents the relationship between the product type at the product level and the item type at the item level. While there are eight possible combinations of ProductType and ItemType, only four of these combinations are actually feasible.

@Value
@Builder
public class Product {
    ProductType productType;

    List<Item> items;

    @Value
    @Builder
    public static class Item {
        ItemType itemType;
    }
}

// The relationship between ProductType and 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,
}
Enter fullscreen mode Exit fullscreen mode

Therefore, we need to set up these four combinations separately, which can be done using @ParameterizedTest and @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
        )
    );
}
Enter fullscreen mode Exit fullscreen mode

Image description

There's also a way to utilize org.junit.jupiter.api.DynamicTest and @TestFactory.

Let's look at the code first. It sets up the four Enum combinations with Stream.of and then runs each through DynamicTest.dynamicTest within a flatMap structure.

@TestFactory // It's not @Test but @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);
                        }
                    )
                )
        );
    }
}
Enter fullscreen mode Exit fullscreen mode

Image description

Java doesn't provide a Pair class by default, so using Map made the implementation a bit complicated, requiring the use of flatMap.

Creating it with Kotlin and using Pair would indeed make it simpler.

@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}")
            }
        }
}
Enter fullscreen mode Exit fullscreen mode

cf) While Java doesn't provide a Pair class by default, we can use org.springframework.data.util.Pair provided by Spring.

Top comments (0)