[JUnit5] - @Nested ํ…Œ์ŠคํŠธ ์ˆœ์„œ ์ง€์ •

๐Ÿ› ๏ธ ๊ฐœ๋ฐœ ํ™˜๊ฒฝ

๐Ÿƒ Spring : Spring Boot 2.7.8

๐Ÿ› ๏ธ Java : Amazon corretto 17

@Nested

@Nested is used to signal that the annotated class is a nested, non-static test class (i.e., an inner class) that can share setup and state with an instance of its enclosing class.
The enclosing class may be a top-level test class or another @Nested test class, and nesting can be arbitrarily deep.
non-static ํด๋ž˜์Šค(๋‚ด๋ถ€ ํด๋ž˜์Šค)์ž„์„ ์‹œ๊ทธ๋„๋งํ•˜๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉ๋˜๋ฉฐ, ์ตœ์ƒ์œ„ ํ…Œ์ŠคํŠธ ํด๋ž˜์Šค๋ฅผ ์‚ฌ์šฉํ•  ๋•Œ ์„ ์–ธํ•œ๋‹ค.

์ฆ‰, ํ•œ ํ…Œ์ŠคํŠธ์— ๋‚ด๋ถ€ ํด๋ž˜์Šค๋ฅผ ์ƒ์„ฑํ•ด ์—ฌ๋Ÿฌ ํ…Œ์ŠคํŠธ๋ฅผ ๋ฌถ๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด๋‹ค.

@AutoConfigureMockMvc
@SpringBootTest(webEnvironment = WebEnvironment.MOCK)
class ControllerTest {

    ...

    @Test
    @DisplayName("์ €์žฅ ์‹คํŒจ - ์ œ๋ชฉ ๋ฐ์ดํ„ฐ ๋ˆ„๋ฝ")
    void saveTest1(){
        ...
    }

    @Test
    @DisplayName("์ €์žฅ ์‹คํŒจ - ๋‚ด์šฉ ๋ฐ์ดํ„ฐ ๋ˆ„๋ฝ")
    void saveTest2(){
        ...
    }

    @Test
    @DisplayName("์ €์žฅ ์„ฑ๊ณต")
    void saveTest3(){
        ...
    }

    @Test
    @DisplayName("์ˆ˜์ • ์‹คํŒจ - ์ œ๋ชฉ ๋ฐ์ดํ„ฐ ๋ˆ„๋ฝ")
    void updateTest1(){
        ...
    }
}

์œ„ ์ฝ”๋“œ์™€ ํ•œ ํ…Œ์ŠคํŠธ ํด๋ž˜์Šค์— ์—ฌ๋Ÿฌ ํ…Œ์ŠคํŠธ๊ฐ€ ๋“ค์–ด๊ฐ€๊ฒŒ ๋œ๋‹ค.
์ด๋Ÿด ๊ฒฝ์šฐ ์œ„ ์‚ฌ์ง„๊ณผ ๊ฐ™์ด ํ…Œ์ŠคํŠธ ์ˆœ์„œ๋„ ๋ณด์žฅ๋˜์ง€ ์•Š์œผ๋ฉฐ, ๊ฐ™์€ ๊ด€์‹ฌ์‚ฌ๋ผ๋ฆฌ ๋ฌถ์ด์ง€๋„ ์•Š๋Š”๋‹ค.
์ด๋Ÿฌํ•œ ์ƒํ™ฉ์„ ๋ฐฉ์ง€ํ•˜๊ณ ์ž, ๊ฐ™์€ ๊ด€์‹ฌ์‚ฌ์˜ ํ…Œ์ŠคํŠธ๋ฅผ ๋ฌถ๋„๋ก ๋„์™€์ฃผ๋Š” ๊ธฐ๋Šฅ์ด @Nested์ด๋‹ค.

@AutoConfigureMockMvc
@SpringBootTest(webEnvironment = WebEnvironment.MOCK)
class ControllerTest {

    @Nested
    @DisplayName("์ €์žฅ ํ…Œ์ŠคํŠธ")
    class SaveTest {
        @Test
        @DisplayName("์ €์žฅ ์‹คํŒจ - ์ œ๋ชฉ ๋ฐ์ดํ„ฐ ๋ˆ„๋ฝ")
        void saveTest1(){
            ...
        }

        @Test
        @DisplayName("์ €์žฅ ์‹คํŒจ - ๋‚ด์šฉ ๋ฐ์ดํ„ฐ ๋ˆ„๋ฝ")
        void saveTest2(){
            ...
        }

        @Test
        @DisplayName("์ €์žฅ ์„ฑ๊ณต")
        void saveTest3(){
            ...
        }
    }

    @Nested
    @DisplayName("์ˆ˜์ • ํ…Œ์ŠคํŠธ")
    class UpdateTest {
        @Test
        @DisplayName("์ˆ˜์ • ์‹คํŒจ ํ…Œ์ŠคํŠธ - ์ œ๋ชฉ ๋ฐ์ดํ„ฐ ๋ˆ„๋ฝ")
        void updateTest1(){
            ...
        }
    }
}

์œ„์™€ ๊ฐ™์ด @Nested๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ๊ฐ ๊ด€์‹ฌ์‚ฌ๋ฅผ ํ•œ ํด๋ž˜์Šค๋กœ ๋ฌถ์–ด ํ…Œ์ŠคํŠธํ•  ์ˆ˜ ์žˆ๋‹ค.

@Order()

@Order ์–ด๋…ธํ…Œ์ด์…˜์„ ์‚ฌ์šฉํ•˜๋ฉด ํ…Œ์ŠคํŠธ์˜ ์ˆœ์„œ๋ฅผ ์ •ํ•  ์ˆ˜ ์žˆ๋‹ค. ํ•ด๋‹น ์–ด๋…ธํ…Œ์ด์…˜์˜ API ๋ฌธ์„œ๋ฅผ ์‚ดํŽด๋ณด๋ฉด ์•„๋ž˜์™€ ๊ฐ™์€ ๋‚ด์šฉ์ด ์žˆ๋‹ค.

 

@Order is an annotation that is used to configure the order in which the annotated element (i.e., field, method, or class) should be evaluated or executed relative to other elements of the same category.
When used with @RegisterExtension or @ExtendWith, the category applies to extension fields.
When used with MethodOrderer.OrderAnnotation, the category applies to test methods.
When used with ClassOrderer.OrderAnnotation, the category applies to test classes.
@Order ์–ด๋…ธํ…Œ์ด์…˜์ด ๋ถ™์€ ์š”์†Œ(ํ•„๋“œ, ๋ฉ”์†Œ๋“œ, ํด๋ž˜์Šค)์˜ ์‹คํ–‰ ์ˆœ์„œ๋ฅผ ๊ตฌ์„ฑํ•˜๋Š”๋ฐ ์‚ฌ์šฉ๋œ๋‹ค.
MethodOrderer๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ๋ฉ”์†Œ๋“œ์— ์ ์šฉ๋˜๋ฉฐ, ClassOrderer๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ํ…Œ์ŠคํŠธ ํด๋ž˜์Šค์— ์ ์šฉ๋œ๋‹ค.

์œ„ ๋‚ด์šฉ์œผ๋กœ ์ถ”์ธกํ•ด๋ณด๋ฉด ํ•„๋“œ, ๋ฉ”์†Œ๋“œ, ํด๋ž˜์Šค์— ์ ์šฉํ•  ์ˆ˜ ์žˆ์ง€๋งŒ, ๊ธฐ๋ณธ์ ์œผ๋กœ๋Š” ํ•„๋“œ ํ˜น์€ ๋ฉ”์†Œ๋“œ์—๋งŒ ์ ์šฉ์ด ๋˜๋Š” ๊ฒƒ ๊ฐ™๋‹ค.

@AutoConfigureMockMvc
@SpringBootTest(webEnvironment = WebEnvironment.MOCK)
class ControllerTest {

    @Nested
    @Order(1)
    @DisplayName("์ €์žฅ ํ…Œ์ŠคํŠธ")
    class SaveTest {
        ...
    }

    @Nested
    @Order(2)
    @DisplayName("์ˆ˜์ • ํ…Œ์ŠคํŠธ")
    class UpdateTest {
        ...
    }
}

์‹ค์ œ๋กœ @Nested ์–ด๋…ธํ…Œ์ด์…˜์ด ๋ถ™์€ ํด๋ž˜์Šค์— @Order๋ฅผ ๋ถ™์ผ ๊ฒฝ์šฐ ๋™์ž‘ํ•˜์ง€ ์•Š๋Š”๋‹ค.
API ์„ค๋ช…์— ๋‚˜์™€์žˆ๋“ฏ์ด @Order์˜ ๋ฒ”์œ„๋ฅผ ClassOrderer๋กœ ์ง€์ •ํ•ด์ค˜์•ผ์ง€ @Nested์—๋„ ์ ์šฉํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋œ๋‹ค.

@AutoConfigureMockMvc
@TestClassOrder(ClassOrderer.OrderAnnotation.class)
@SpringBootTest(webEnvironment = WebEnvironment.MOCK)
class ControllerTest {

    @Nested
    @Order(1)
    @DisplayName("์ €์žฅ ํ…Œ์ŠคํŠธ")
    class SaveTest {
        ...
    }

    @Nested
    @Order(2)
    @DisplayName("์ˆ˜์ • ํ…Œ์ŠคํŠธ")
    class UpdateTest {
        ...
    }
}

์œ„ ์ฝ”๋“œ์ฒ˜๋Ÿผ ์ตœ์ƒ๋‹จ ํ…Œ์ŠคํŠธ ํด๋ž˜์Šค์— @TestClassOrder ์–ด๋…ธํ…Œ์ด์…˜์„ ๋ถ™์—ฌ ClassOrderer๋กœ ์ง€์ •ํ•ด์ฃผ๋ฉด ๋œ๋‹ค.
์ด๋Ÿด ๊ฒฝ์šฐ ํด๋ž˜์Šค์— ๋Œ€ํ•œ ์ˆœ์„œ๋„ ์ง€์ •ํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ, ๋ฉ”์†Œ๋“œ์˜ ์ˆœ์„œ๋„ ๊ธฐ์กด์ฒ˜๋Ÿผ ์ง€์ •ํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋œ๋‹ค.