Skip to content

Latest commit

ย 

History

History
847 lines (584 loc) ยท 24.2 KB

Junit5.md

File metadata and controls

847 lines (584 loc) ยท 24.2 KB

๐Ÿ’ก JUnit

์ž๋ฐ” ๊ฐœ๋ฐœ์ž๊ฐ€ ๊ฐ€์žฅ ๋งŽ์ด ์‚ฌ์šฉํ•˜๋Š” ํ…Œ์ŠคํŒ… ํ”„๋ ˆ์ž„์›Œํฌ

  • Java 8 ์ด์ƒ์ด ํ•„์š”ํ•˜๋‹ค.
  • ๋Œ€์ฒด์ œ๋กœ TestNg, Spock๋“ฑ ๋งŽ์ง€๋งŒ JUnit๋งŒ ์•Œ์•„๋„ ๋ฌธ์ œ์—†๋‹ค.

JUnit 4์™€ JUnit 5์˜ ์ฐจ์ด์ 

JUnit 4 JUnit 5
@Before
@BeforeClass
@After
@BeforeEach
@BeforeAll
@AfterEach
Public void ...
์ ‘๊ทผ์ œ์–ด์ž public ๊ธฐ๋ณธ์œผ๋กœ ์‚ฌ์šฉ
void ...
์ ‘๊ทผ์ œ์–ด์ž Default ์‚ฌ์šฉ



Platform : ํ…Œ์ŠคํŠธ๋ฅผ ์‹คํ–‰ํ•ด ์ฃผ๋Š” ๋Ÿฐ์ฒ˜๋ฅผ ์ œ๊ณตํ•ด ์ค€๋‹ค. TestEngine API ์ œ๊ณต
Jupiter : TestEngine API ๊ตฌํ˜„์ฒด๋กœ JUnit 5๋ฅผ ์ œ๊ณตํ•œ๋‹ค.
Vintage : JUnit4์™€ 3์„ ์ง€์›ํ•˜๋Š” TestEngine ๊ตฌํ˜„์ฒด์ด๋‹ค.



โœ… JUnit 5

JUnit5๊ฐ€ ์ œ๊ณตํ•˜๋Š” ๊ธฐ๋ณธ ์–ด๋…ธํ…Œ์ด์…˜

class StudyTest {

    @Test
    void create() {
        Study study = new Study();
        assertNotNull(study);
        System.out.println("create");
    }

    @Test
    void create1() {
        System.out.println("create1");
    }

    @BeforeAll
    static void beforeAll() {
        System.out.println("before all");
    }

    @AfterAll
    static void afterAll() {
        System.out.println("after all");
    }

    @BeforeEach
    void beforeEach() {
        System.out.println("before each");
    }

    @AfterEach
    void afterEach() {
        System.out.println("after each");
    }
    
}

@Test

  • ํ•ด๋‹น ๋ฉ”์„œ๋“œ๋ฅผ ํ…Œ์ŠคํŠธ ๋Œ€์ƒ์œผ๋กœ ์ง€์ •ํ•œ๋‹ค.

@BeforeAll

  • ๋ชจ๋“  ํ…Œ์ŠคํŠธ ์‹œ์ž‘ ์ „์— ์ˆ˜ํ–‰๋˜๋Š” ๋กœ์ง์— ๋ถ™๋Š” ์–ด๋…ธํ…Œ์ด์…˜์œผ๋กœ static์„ ๋ถ™์—ฌ์ค˜์•ผ ํ•˜๋ฉฐ, ์ ‘๊ทผ ์ œ์–ด์ž๋Š” default ์ด์ƒ์ด์–ด์•ผ ํ•œ๋‹ค.

@AfterAll

  • ๋ชจ๋“  ํ…Œ์ŠคํŠธ ์ข…๋ฃŒ ํ›„์— ์ˆ˜ํ–‰๋˜๋Š” ๋กœ์ง์— ๋ถ™๋Š” ์–ด๋…ธํ…Œ์ด์…˜์œผ๋กœ static์„ ๋ถ™์—ฌ์ค˜์•ผ ํ•˜๋ฉฐ, ์ ‘๊ทผ ์ œ์–ด์ž๋Š” default ์ด์ƒ์ด์–ด์•ผ ํ•œ๋‹ค.

@BeforeEach

  • ๋ชจ๋“  @Test ์–ด๋…ธํ…Œ์ด์…˜์ด ๋ถ™์€ ํ…Œ์ŠคํŠธ ๋Œ€์ƒ ๋ฉ”์„œ๋“œ ์ˆ˜ํ–‰ ์ „๋งˆ๋‹ค ์ˆ˜ํ–‰๋œ๋‹ค.

@AfterEach

  • ๋ชจ๋“  @Test ์–ด๋…ธํ…Œ์ด์…˜์ด ๋ถ™์€ ํ…Œ์ŠคํŠธ ๋Œ€์ƒ ๋ฉ”์„œ๋“œ ์ˆ˜ํ–‰ ์ข…๋ฃŒ ์‹œ๋งˆ๋‹ค ์ˆ˜ํ–‰๋œ๋‹ค.

@Disabled

  • ํ•ด๋‹น ์–ด๋…ธํ…Œ์ด์…˜์ด ๋ถ™์€ ๋ฉ”์„œ๋“œ๋Š” ํ…Œ์ŠคํŠธ ์ œ์™ธ ๋Œ€์ƒ์œผ๋กœ ํ…Œ์ŠคํŠธ๋ฅผ ์ˆ˜ํ–‰ํ•˜์ง€ ์•Š๋Š”๋‹ค.



โœ… JUnit 5 ํ…Œ์ŠคํŠธ ์ด๋ฆ„ ํ‘œ์‹œ

@DisplayName

  • ํ…Œ์ŠคํŠธ ์ด๋ฆ„์„ ๋ณด๊ธฐ ์‰ฝ๊ฒŒ ํ‘œํ˜„ํ•˜๋Š” ์–ด๋…ธํ…Œ์ด์…˜

    • ์šฐ์„ ์ˆœ์œ„๋Š”@DisplayNameGeneration๋ณด๋‹ค ๋†’๋‹ค.

    • ์ด๋ชจ์ง€๊ฐ™์€ ์ด๋ชจํ‹ฐ์ฝ˜๋„ ์ง€์›์„ ํ•œ๋‹ค.

    • ํ•ด๋‹น ์• ๋…ธํ…Œ์ด์…˜ ์—ญ์‹œ ํด๋ž˜์Šค์™€ ๋ฉ”์„œ๋“œ ๋ชจ๋‘ ๋ถ™์—ฌ์ค„ ์ˆ˜ ์žˆ๋‹ค.


@DisplayName("ํ…Œ์ŠคํŠธ ํด๋ž˜์Šค")
public class TestClass {
	...
	@DisplayName("ํšŒ์› ์ƒ์„ฑ ํ…Œ์ŠคํŠธ")
	@Test
	void create_account_test(){
		...
	}
}



โœ… JUnit 5 Assertion

๐Ÿ’ก ์‹ค์ œ ํ…Œ์ŠคํŠธ์—์„œ ๊ฒ€์ฆํ•˜๊ณ ์ž ํ•˜๋Š” ๋‚ด์šฉ์„ ํ™•์ธ


๊ตฌํ˜„ํ•œ ๊ธฐ๋Šฅ์ด ์˜ˆ์ธกํ•œ ๋Œ€๋กœ ๋‚˜์˜ค๋Š”์ง€ ํ™•์ธํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” ์ด๋ฅผ ๊ฒ€์ฆํ•ด ์ค„ ๊ธฐ๋Šฅ์ด ํ•„์š”ํ•˜๋‹ค.
org.junit.jupiter.api.Assertions์—์„œ๋Š” ๊ฒ€์ฆ์„ ์œ„ํ•œ ๋‹ค์–‘ํ•œ ๋ฉ”์„œ๋“œ๋ฅผ ์ œ๊ณตํ•ด ์ค€๋‹ค.



assertEquals(expected, actual)

  • ๊ธฐ๋Œ€ํ•œ ๊ฐ’(expected)์ด ์‹ค์ œ ๊ฐ’(actual)๊ณผ ๊ฐ™์€์ง€ ํ™•์ธํ•˜๋Š” ๋ฉ”์„œ๋“œ
@DisplayName("์Šคํ„ฐ๋”” ๋งŒ๋“ค๊ธฐ ")
@Test
void create_new_study() {
    Study study = new Study();
    assertEquals(StudyStatus.DRAFT, study.getStatus(),()-> "์Šคํ„ฐ๋””๋ฅผ ์ฒ˜์Œ ๋งŒ๋“ค๋ฉด DRAFT ์ƒํƒœ๋‹ค. ");
}

  • assertEquals์—์„œ๋Š” ์„ธ ๋ฒˆ์งธ ํŒŒ๋ผ๋ฏธํ„ฐ๋กœ ๋ฉ”์‹œ์ง€๋ฅผ ์ค„ ์ˆ˜ ์žˆ๋‹ค.

    • ํ•ด๋‹น ํ…Œ์ŠคํŠธ๊ฐ€ ํ†ต๊ณผํ•˜์ง€ ๋ชปํ–ˆ์„ ๊ฒฝ์šฐ ์ถœ๋ ฅ๋œ๋‹ค.

    • ์ด๋•Œ Supplier<_String_> ํƒ€์ž…์˜ ์ธ์Šคํ„ด์Šค๋ฅผ ๋žŒ๋‹ค๋กœ ์ œ๊ณตํ•  ์ˆ˜๋„ ์žˆ๋Š”๋ฐ, ๋ณต์žกํ•œ ๋ฉ”์‹œ์ง€๋ฅผ ์ƒ์„ฑํ•ด์•ผ ํ•˜๋Š” ๊ฒฝ์šฐ ๋žŒ๋‹ค๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์‹คํŒจํ•œ ๊ฒฝ์šฐ์—๋งŒ ํ•ด๋‹น ๋ฉ”์‹œ์ง€๋ฅผ ๋งŒ๋“ค ์ˆ˜ ์žˆ์–ด ํšจ์œจ์ ์ด๋‹ค.



assertNotNull(actual)

  • ๊ฒฐ๊ณผ ๊ฐ’(actual)์ด null ์ธ์ง€ ์•„๋‹Œ์ง€ ํ™•์ธํ•˜๋Š” ๋ฉ”์„œ๋“œ
@DisplayName("์Šคํ„ฐ๋”” ๋งŒ๋“ค๊ธฐ ")
@Test
void create_new_study() {
    Study study = new Study();
    assertNotNull(study);   
}



assertTrue(boolean)

  • ๋‹ค์Œ ์กฐ๊ฑด์ด ์ฐธ์ธ์ง€ ํ™•์ธํ•˜๋Š” ๋ฉ”์„œ๋“œ
@DisplayName("์Šคํ„ฐ๋”” ๋งŒ๋“ค๊ธฐ ")
@Test
void create_new_study() {
    Study study = new Study();
    assertTrue(study.getStatus().equals(StudyStatus.DRAFT));
}



assertAll(executable...)

  • ๋ชจ๋“  ๊ตฌ๋ฌธ ํ™•์ธ ๋ฉ”์„œ๋“œ
@DisplayName("์Šคํ„ฐ๋”” ๋งŒ๋“ค๊ธฐ ")
@Test
void create_new_study() {
    Study study = new Study();
    assertNotNull(study);

    assertAll(
            ()->assertEquals(StudyStatus.DRAFT, study.getStatus(),()-> "์Šคํ„ฐ๋””๋ฅผ ์ฒ˜์Œ ๋งŒ๋“ค๋ฉด DRAFT ์ƒํƒœ๋‹ค. "),
            ()->assertTrue(study.getLimit() > 0, ()-> "์Šคํ„ฐ๋”” ์ตœ๋Œ€ ์ฐธ์„ ๊ฐ€๋Šฅ ์ธ์›์€ 0๋ช… ์ด์ƒ์ด์–ด์•ผ ํ•œ๋‹ค. ")
    );
}



assertThrows(expectedType, executable)

  • ์˜ˆ์™ธ ๋ฐœ์ƒ ํ™•์ธ ๋ฉ”์„œ๋“œ

    • ์˜ˆ์™ธ ๊ฒ€์ฆ ํ›„ ํ•ด๋‹น ์˜ˆ์™ธ๋ฅผ ๋ฐ˜ํ™˜ํ•ด์ฃผ๊ธฐ์— ์˜ˆ์™ธ ๋ฉ”์‹œ์ง€ ๊ฒ€์ฆ์ด ๊ฐ€๋Šฅํ•˜๋‹ค.
@DisplayName("์Šคํ„ฐ๋”” ๋งŒ๋“ค๊ธฐ ")
@Test
void create_new_study() {
    IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, () -> new Study(-1));
    assertEquals(exception.getMessage(), "limit ์€ 0๋ณด๋‹ค ์ปค์•ผํ•œ๋‹ค.");
}



assertTimeout(duration, executable)

  • ํŠน์ • ์‹œ๊ฐ„ ๋‚ด์— ์‹คํ–‰ ์™„๋ฃŒ๋˜๋Š”์ง€ ํ™•์ธํ•˜๋Š” ๋ฉ”์„œ๋“œ
@DisplayName("์Šคํ„ฐ๋”” ๋งŒ๋“ค๊ธฐ ")
@Test
void create_new_study() {
    assertTimeout(Duration.ofMillis(100), () -> {
        new Study(10);
        Thread.sleep(300);
    });
}

๐Ÿ’ก sleep ๋ฉ”์„œ๋“œ๋ฅผ ํ†ตํ•ด 300ms ๋Œ€๊ธฐํ•˜๊ธฐ์— ํ•ด๋‹น ํ…Œ์ŠคํŠธ๋Š” ์‹คํŒจํ•œ๋‹ค.


๋งŒ์•ฝ 300ms๋ฅผ ๋‹ค ๊ธฐ๋‹ค๋ฆฌ์ง€ ์•Š๊ณ  ํ•ด๋‹น ๋Œ€๊ธฐ์‹œ๊ฐ„(100ms)๊ฐ€ ์ง€๋‚˜ ํ…Œ์ŠคํŠธ๊ฐ€ ์‹คํŒจํ•˜์ž๋งˆ์ž ํ…Œ์ŠคํŠธ๊ฐ€ ์ค‘๋‹จ๋˜๋„๋ก ํ•˜๋ ค๋ฉด assertTimeoutPreemtively() ๋ฉ”์„œ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ๋œ๋‹ค.

ํ•˜์ง€๋งŒ, ์Šคํ”„๋ง ํŠธ๋žœ์žญ์…˜์ด ์ œ๋Œ€๋กœ ๋™์ž‘์„ ์•ˆ ํ•  ์ˆ˜ ์žˆ์–ด์„œ ๋กค๋ฐฑ ๊ธฐ๋ฐ˜์ธ ์Šคํ”„๋ง ํ…Œ์ŠคํŠธ์—์„œ ๋กค๋ฐฑ์ด ์•ˆ๋œ๋‹ค๋˜๊ฐ€ ํ•˜๋Š” ๋ถ€์ž‘์šฉ์ด ์žˆ๊ธฐ์— ์‚ฌ์šฉ์„ ๊ถŒ์žฅํ•˜์ง€๋Š” ์•Š๋Š”๋‹ค.

ThreadLocal ๊ฐ™์€ ์Šค๋ ˆ๋“œ์™€ ์ „ํ˜€ ๊ด€๋ จ์ด ์—†๋Š” ์ฝ”๋“œ๋ฅผ ์‹คํ–‰ํ•  ๋•Œ๋Š” ์‚ฌ์šฉํ•ด๋„ ๊ดœ์ฐฎ๋‹ค.



โœ… ์กฐ๊ฑด์— ๋”ฐ๋ผ ํ…Œ์ŠคํŠธ ์‹คํ–‰

  • JUnit์—์„œ๋Š” ํŠน์ •ํ•œ ์กฐ๊ฑด์— ๋”ฐ๋ผ ํ…Œ์ŠคํŠธ๋ฅผ ์‹คํ–‰ํ•  ์ˆ˜๋„ ์žˆ๋‹ค.

    • ex) ํŠน์ •ํ•œ OS, ํ™˜๊ฒฝ ๋ณ€์ˆ˜, ์‹œ์Šคํ…œ ๋ณ€์ˆ˜์— ๋”ฐ๋ผ ํ…Œ์ŠคํŠธ ์‹คํ–‰ ๊ฒฐ์ •

org.junit.jupiter.api.Assumptions.*


  • assumeTrue(condition)

    • ํ•ด๋‹น ์กฐ๊ฑด์ด ํ†ต๊ณผ๋ฅผ ํ•ด์•ผ ์•„๋ž˜ ๋กœ์ง๋“ค ์ˆ˜ํ–‰

  • assumingThat(condition, test)

    • ์กฐ๊ฑด(condition)์ด ํ†ต๊ณผ๋ฅผ ํ•˜๋ฉด ๋‘ ๋ฒˆ์งธ ํŒŒ๋ผ๋ฏธํ„ฐ๋กœ ์ „๋‹ฌํ•œ ๋กœ์ง ์ˆ˜ํ–‰

@DisplayName("์Šคํ„ฐ๋”” ๋งŒ๋“ค๊ธฐ ")
@Test
void create_new_study() {
    String test_evn = System.getenv("TEST_ENV");
    System.out.println(test_evn);

    assumeTrue("LOCAL".equalsIgnoreCase(test_evn));
    assumingThat("LOCAL".equalsIgnoreCase(test_evn), () -> {
        System.out.println("local");
        Study actual = new Study(100);
        assertTrue(actual.getLimit() >= 0);
    });

    assumingThat("hong".equalsIgnoreCase(test_evn), () -> {
        System.out.println("hong");
        Study actual = new Study(10);
        assertTrue(actual.getLimit() >= 0);
    });
}



์–ด๋…ธํ…Œ์ด์…˜์œผ๋กœ ์กฐ๊ฑด ์„ค์ •

  • @EnabledOnOs
    • ํŠน์ • OS์ผ ๋•Œ๋งŒ ํ…Œ์ŠคํŠธ๊ฐ€ ๋™์ž‘ํ•˜๊ฒŒ ํ•  ์ˆ˜๋„ ์žˆ๋‹ค.
    • (@EnabledOnOs(OS.MAC))

  • @EnabledOnJre
    • ํŠน์ • JRE๋ฒ„์ „์ผ ๋•Œ๋งŒ ํ…Œ์ŠคํŠธ๊ฐ€ ๋™์ž‘ํ•˜๊ฒŒ ํ•  ์ˆ˜๋„ ์žˆ๋‹ค.
    • (@EnabledOnJre({JRE.JAVA_8, JRE.JAVA_9, JRE.JAVA_10, JRE.JAVA_11}))

  • @EnabledIfEnvironmentVariable
    • ์œ„์—์„œ ์‚ฌ์šฉํ•œ assumeXX ๋ฉ”์„œ๋“œ๋Š” ํ•ด๋‹น ์–ด๋…ธํ…Œ์ด์…˜์„ ํ†ตํ•ด ํ™˜๊ฒฝ ๋ณ€์ˆ˜ ์กฐ๊ฑด ์„ค์ •์ด ๊ฐ€๋Šฅํ•˜๋‹ค.
    • (@EnabledIfEnvironmentVariable(named = "TEST_ENV", matches = "local"))



โœ… ํƒœ๊น…๊ณผ ํ•„ํ„ฐ๋ง

  • ์—ฌ๋Ÿฌ ๊ฐœ์˜ ์ž‘์„ฑํ•œ ํ…Œ์ŠคํŠธ๋ฅผ ๊ทธ๋ฃนํ™”ํ•  ์ˆ˜ ์žˆ๋‹ค. (ex: ๋ชจ๋“ˆ ๋ณ„, ๋‹จ์œ„/ํ†ตํ•ฉ ๊ตฌ๋ถ„, ๊ธฐํƒ€ ์กฐ๊ฑด)

@Tag

  • ํ•˜๋‚˜์— ํ…Œ์ŠคํŠธ ๋ฉ”์„œ๋“œ์— ์—ฌ๋Ÿฌ ํƒœ๊ทธ๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜๋„ ์žˆ๋‹ค.
class StudyTest {

    @DisplayName("์Šคํ„ฐ๋”” ๋งŒ๋“ค๊ธฐ fast")
    @Test
    @Tag("fast")
    void create_new_study() {
        Study study = new Study();
        assertEquals(StudyStatus.DRAFT, study.getStatus(), ()-> "์Šคํ„ฐ๋””๋ฅผ ์ฒ˜์Œ ๋งŒ๋“ค๋ฉด DRAFT ์ƒํƒœ๋‹ค. ");
    }
    
    
    @DisplayName("์Šคํ„ฐ๋”” ๋งŒ๋“ค๊ธฐ slow")
    @Test
    @Tag("slow")
    void create_new_study_again() {
        Study study = new Study();
        assertEquals(StudyStatus.DRAFT, study.getStatus(), ()-> "์Šคํ„ฐ๋””๋ฅผ ์ฒ˜์Œ ๋งŒ๋“ค๋ฉด DRAFT ์ƒํƒœ๋‹ค. ");
    }
}

์Šคํ„ฐ๋”” ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•˜๋Š” ํ…Œ์ŠคํŠธ ๋‘ ๊ฐœ๋ฅผ ๊ฐ๊ฐ slow, fast ํƒœ๊ทธ๋กœ ๊ตฌ๋ถ„ ํ–ˆ์ง€๋งŒ,
์‹คํ–‰ ์‹œ ๋‘˜ ๋‹ค ์ˆ˜ํ–‰๋˜๋Š” ๊ฒƒ์„ ๋ณผ์ˆ˜ ์žˆ๋‹ค. ์ด๋Š” ํ•„ํ„ฐ๋ง์„ ํ•ด์ฃผ์ง€ ์•Š์•˜๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.


ํ•„ํ„ฐ๋ง

  • IntelliJ์—์„œ ํŠน์ • ํƒœ๊ทธ๋กœ ํ…Œ์ŠคํŠธ ํ•„ํ„ฐ๋ง

    • Run/Debug Configurations์—์„œ Tags ํ•ญ๋ชฉ์œผ๋กœ ์„ ํƒ ํ›„ ์‹คํ–‰ํ•  ํ…Œ์ŠคํŠธ์˜ ํƒœ๊ทธ๋ช…์„ ์ ์–ด์ฃผ๋ฉด ๋œ๋‹ค.

  • Maven - pom.xml ์ž‘์„ฑ์„ ํ†ตํ•œ ํ•„ํ„ฐ๋ง
<profiles>
    <profile>
        <id>default</id>
        <activation>
            <activeByDefault>true</activeByDefault>
        </activation>
        <build>
            <plugins>
                <plugin>
                    <artifactId>maven-surefire-plugin</artifactId>
                    <configuration>
                        <groups>fast</groups>
                    </configuration>
                </plugin>
            </plugins>
        </build>
    </profile>
</profiles>
  • ๋งŒ์•ฝ slow๋„ ํ…Œ์ŠคํŠธ๋ฅผ ํ•˜๊ณ  ์‹ถ๋‹ค๋ฉด or ๋ฌธ๋ฒ•์ธ | ์—ฐ์‚ฐ์ž๋ฅผ ์ด์šฉํ•ด์„œ ์ž‘์„ฑ์„ ํ•ด์ฃผ๋ฉด ๋œ๋‹ค. <groups>fast | slow</groups>



โœ… ์ปค์Šคํ…€ ํƒœ๊ทธ

JUnit์—์„œ ์ œ๊ณตํ•˜๋Š” ํ…Œ์ŠคํŠธ์šฉ ์–ด๋…ธํ…Œ์ด์…˜์€ ๋ฉ”ํƒ€ ์–ด๋…ธํ…Œ์ด์…˜์œผ๋กœ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค. ์ž์ฃผ ์‚ฌ์šฉํ•˜๋Š” ์–ด๋…ธํ…Œ์ด์…˜์˜ ์กฐํ•ฉ์„ ํ•˜๋‚˜์˜ ComposedAnnotation์œผ๋กœ ๋งŒ๋“ค์–ด์„œ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

Fast๋ผ๋Š” ์ž„์˜์˜ ์–ด๋…ธํ…Œ์ด์…˜์„ ๋งŒ๋“ค์–ด์„œ ๋ฉ”ํƒ€ ์–ด๋…ธํ…Œ์ด์…˜์„ ์ •์˜ํ•ด ๋ณด์ž.


์ฝ”๋“œ

FastTest

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Test
@Tag("fast")
public @interface FastTest { }

SlowTest

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Test
@Tag("slow")
public @interface SlowTest { }

StudyTest

class StudyTest {

    @DisplayName("์Šคํ„ฐ๋”” ๋งŒ๋“ค๊ธฐ fast")
    @FastTest
    void create_new_study() {
        Study study = new Study();
        assertEquals(StudyStatus.DRAFT, study.getStatus(),()-> "์Šคํ„ฐ๋””๋ฅผ ์ฒ˜์Œ ๋งŒ๋“ค๋ฉด DRAFT ์ƒํƒœ๋‹ค. ");
    }
    
   
    @DisplayName("์Šคํ„ฐ๋”” ๋งŒ๋“ค๊ธฐ slow")
    @SlowTest
    void create_new_study_again() {
        Study study = new Study();
        assertEquals(StudyStatus.DRAFT, study.getStatus(),()-> "์Šคํ„ฐ๋””๋ฅผ ์ฒ˜์Œ ๋งŒ๋“ค๋ฉด DRAFT ์ƒํƒœ๋‹ค. ");
    }
    
}

  • ๊ธฐ์กด์— ์ž‘์„ฑ๋ผ์žˆ๋˜ @Test, @Tag("fast or slow") ์–ด๋…ธํ…Œ์ด์…˜์ด ์‚ฌ๋ผ์ง€๊ณ  ์ž„์˜๋กœ ์ž‘์„ฑํ•œ ์–ด๋…ธํ…Œ์ด์…˜(@FastTest, @SlowTest)

  • ๋งค๋ฒˆ Tag๋ฅผ ์ง์ ‘ ์ž…๋ ฅํ•˜๋ฉด ์˜คํƒ€๊ฐ€ ๋‚  ํ™•๋ฅ ์ด ์žˆ๋Š”๋ฐ ๋ฉ”ํƒ€ ์–ด๋…ธํ…Œ์ด์…˜์œผ๋กœ ์ด๋ฅผ ํ•ด๊ฒฐํ•œ๋‹ค.



ํ…Œ์ŠคํŠธ ๋ฐ˜๋ณตํ•˜๊ธฐ

์ธ์ž๊ฐ€ ๋žœ๋ค ๊ฐ’์ด๊ฑฐ๋‚˜, ํ…Œ์ŠคํŠธ ๋ฐœ์ƒ ์‹œ์ ์— ๋”ฐ๋ผ ๋‹ฌ๋ผ์ง€๋Š” ๊ฐ’ ๋•Œ๋ฌธ์—, ํ…Œ์ŠคํŠธ ๋‚ด์šฉ์ด ๋ฐ˜๋ณต๋ผ์•ผ ํ•˜๋Š” ๊ฒฝ์šฐ์—๋Š” ์–ด๋–ป๊ฒŒ ํ•ด์•ผ ํ• ๊นŒ โ“

JUnit์—์„œ๋Š” ์ด๋Ÿฌํ•œ ํ…Œ์ŠคํŠธ ๋ฐ˜๋ณต์„ ์œ„ํ•œ ์–ด๋…ธํ…Œ์ด์…˜์„ ์ œ๊ณตํ•œ๋‹ค.


@RepeatedTest

  • ์†์„ฑ์„ ํ†ตํ•ด ๋ฐ˜๋ณต ํšŸ์ˆ˜์™€ ๋ฐ˜๋ณต ํ…Œ์ŠคํŠธ ์ด๋ฆ„์„ ์„ค์ •ํ•  ์ˆ˜ ์žˆ๋‹ค.
@DisplayName("๋ฐ˜๋ณต ํ…Œ์ŠคํŠธ")
@RepeatedTest(value = 10, name = "{displayName} {currentRepetition}/{totalRepetitions}")
void repeatTest(RepetitionInfo repetitionInfo) {
    System.out.println("repetitionInfo.getCurrentRepetition() = " + repetitionInfo.getCurrentRepetition());
    System.out.println("repetitionInfo.getTotalRepetitions() = " + repetitionInfo.getTotalRepetitions());
}

  • RepetitionInfo ํƒ€์ž…์˜ ์ธ์ž๋ฅผ ๋ฐ›์„ ์ˆ˜ ์žˆ๋‹ค. ํ•ด๋‹น ์ธ์ž์—๋Š” ๋ฐ˜๋ณต์— ๋Œ€ํ•œ ์ •๋ณด๋ฅผ ์–ป์„ ์ˆ˜ ์žˆ๋‹ค.

  • ์–ด๋…ธํ…Œ์ด์…˜์˜ name ์†์„ฑ์— ํ…Œ์ŠคํŠธ ์ด๋ฆ„, ๋ฐ˜๋ณต ํšŸ์ˆ˜ ๋“ฑ์„ ์„ค์ •ํ•  ์ˆ˜ ์žˆ๋‹ค.

    • {displayName} : @DisplayName์œผ๋กœ ์„ค์ •ํ•œ ํ…Œ์ŠคํŠธ ์ด๋ฆ„
    • {currentRepetition} : ํ˜„์žฌ ๋ฐ˜๋ณต ํšŸ์ˆ˜ ๊ฐ’
    • {totalRepetition} : ์ „์ฒด ๋ฐ˜๋ณต ํšŸ์ˆ˜



@ParameterizedTest

  • ํ…Œ์ŠคํŠธ์— ์—ฌ๋Ÿฌ ๋‹ค๋ฅธ ๋งค๊ฐœ๋ณ€์ˆ˜๋ฅผ ๋Œ€์ž…ํ•ด๊ฐ€๋ฉฐ ๋ฐ˜๋ณต ์‹คํ–‰ํ•œ๋‹ค.
@ParameterizedTest(name = "{index} {displayName} ๊ณผ๋ชฉ:{0}")
@ValueSource(strings = {"์ˆ˜ํ•™", "์˜์–ด", "๊ตญ์–ด", "์ฒด์œก"})
void create_new_study(String input) {
    System.out.println("input = " + input);
}

  • @ValueSource

    • ์†์„ฑ์— ์„ ์–ธํ•ด ์ค€ ํŒŒ๋ผ๋ฏธํ„ฐ๋ฅผ ์ธ์ž ๊ฐ’์œผ๋กœ ์ „๋‹ฌํ•ด ์ฃผ๋Š”๋ฐ, string ํƒ€์ž…๋ฟ ์•„๋‹ˆ๋ผ ๊ฐ ์›์‹œ ํƒ€์ž…์„ ๋ชจ๋‘ ์ง€์›ํ•œ๋‹ค.

  • @ParameterizedTest(name = "{index} {displayName} ๊ณผ๋ชฉ:{0}")

    • {displayName} : @DisplayName ์–ด๋…ธํ…Œ์ด์…˜์œผ๋กœ ์„ค์ •ํ•œ ํ…Œ์ŠคํŠธ ์ด๋ฆ„
    • {index} : ํ˜„์žฌ ๋ฐ˜๋ณต๋œ ํšŸ์ˆ˜์˜ ์ธ๋ฑ์Šค
    • {arguments} : ์ „๋‹ฌ๋˜๋Š” ์ธ๋ฑ์Šค ์ „์ฒด
    • {0}, {1}... : ํŒŒ๋ผ๋ฏธํ„ฐ๋ฅผ ์ธ๋ฑ์Šค๋กœ ์กฐํšŒํ•  ์ˆ˜ ์žˆ๋‹ค.



์ธ์ž ๊ฐ’๋“ค์˜ ์†Œ์Šค

์œ„์—์„œ @ValueSource์— ๋Œ€ํ•ด ์•Œ์•„๋ดค๋Š”๋ฐ ์ธ์ž ๊ฐ’๋“ค์„ ์ œ๊ณตํ•ด ์ฃผ๋Š” ์–ด๋…ธํ…Œ์ด์…˜์€ ๋” ์žˆ๋‹ค.


@NullSource, @EmptySource, @NullAndEmptySource

  • Null๊ณผ ๊ณต๋ฐฑ๋ฌธ์ž๋ฅผ ์ œ๊ณตํ•ด ์ฃผ๋Š” ์–ด๋…ธํ…Œ์ด์…˜์œผ๋กœ ๊ฐ๊ฐ ์ œ๊ณตํ•ด ์ค„ ์ˆ˜๋„ ์žˆ๊ณ , @NullAndEmptySource๋ฅผ ํ†ตํ•ด ๋‘˜ ๋‹ค ์ œ๊ณตํ•ด ์ค„ ์ˆ˜๋„ ์žˆ๋‹ค.

@EnumSource

  • Enum์˜ ๊ฐ’์„ ์ œ๊ณตํ•ด ์ฃผ๋Š” ์–ด๋…ธํ…Œ์ด์…˜
@DisplayName("์Šคํ„ฐ๋”” ๋งŒ๋“ค๊ธฐ")
@ParameterizedTest(name = "{index} {displayName} ๊ณผ๋ชฉ:{arguments}")
@EnumSource(value = StudyStatus.class)
void create_new_study_again_again(StudyStatus status) {
    System.out.println("status = " + status);
}
//status = DRAFT
//status = COMPLETED

@MethodSource

  • ํŠน์ • ๋ฉ”์„œ๋“œ๋ฅผ ๋งŒ๋“ค์–ด์„œ ์ธ์ž ๊ฐ’์„ ์ „๋‹ฌ๋ฐ›๋Š”๋‹ค.
@DisplayName("์Šคํ„ฐ๋”” ๋งŒ๋“ค๊ธฐ")
@ParameterizedTest(name = "{index} {displayName} ๊ณผ๋ชฉ:{arguments}")
@MethodSource("provideNamesAndLimit")
void create_new_study_again_again(String name, int input) {
    System.out.println("name:" + name + ", limit:" + input);
}

private static Stream<Arguments> provideNamesAndLimit() {
    return Stream.of(
            Arguments.of("์ˆ˜ํ•™", 10),
            Arguments.of("์˜์–ด", 20),
            Arguments.of("๊ตญ์–ด", 30)
    );
}

@CvsSource

  • delimiter๋ฅผ ํ†ตํ•ด ์†์„ฑ์˜ value๋กœ ์„ธํŒ…ํ•œ ๊ฐ’์„ ๊ตฌ๋ถ„ํ•ด์„œ ์ธ์ž๋กœ ์ „๋‹ฌํ•œ๋‹ค.
@DisplayName("์Šคํ„ฐ๋”” ๋งŒ๋“ค๊ธฐ")
@ParameterizedTest(name = "{index} {displayName} ๊ณผ๋ชฉ:{arguments}")
@CsvSource(value = {"์ˆ˜ํ•™:1", "์˜์–ด:2", "๊ตญ์–ด:3", "์ฒด์œก:4"}, delimiter = ':')
void create_new_study_again(String input, int limit) {
    System.out.println("input = " + input);
}

@CvsFileSource

  • ํŒŒ์ผ์„ ์ฝ์–ด์™€์„œ ์ธ์ž๋กœ ์ œ๊ณตํ•˜๋Š” ์–ด๋…ธํ…Œ์ด์…˜

@ArgumentSource

  • ArugmentProvider์˜ ๊ตฌํ˜„์ฒด ํด๋ž˜์Šค๋กœ๋ถ€ํ„ฐ ์ธ์ž ๊ฐ’์„ ์ „๋‹ฌํ•˜๋Š” ์–ด๋…ธํ…Œ์ด์…˜
@DisplayName("์Šคํ„ฐ๋”” ๋งŒ๋“ค๊ธฐ")
@ParameterizedTest(name = "{index} {displayName} ๊ณผ๋ชฉ:{arguments}")
@ArgumentsSource(value = TestArgumentProvider.class)
void create_new_study_again(String input) {
    System.out.println("input = " + input);
}

static class TestArgumentProvider implements ArgumentsProvider{

    @Override
    public Stream<? extends Arguments> provideArguments(ExtensionContext extensionContext) throws Exception {
        return Stream.of(
                Arguments.of("์ˆ˜ํ•™", 10),
                Arguments.of("์˜์–ด", 20),
                Arguments.of("๊ตญ์–ด", 30)
        );
    }
}



์ธ์ž ๊ฐ’ ํƒ€์ž… ๋ณ€ํ™˜

์–ด๋…ธํ…Œ์ด์…˜์˜ ์†์„ฑ์œผ๋กœ String์„ ๊ฐ’์„ ์ „๋‹ฌํ•˜๋”๋ผ๋„ ์‹ค์ œ๋กœ๋Š” ๋‹ค๋ฅธ ํƒ€์ž…์œผ๋กœ ์“ฐ๊ณ  ์‹ถ์„ ์ˆ˜ ์žˆ๋‹ค.
JUnit์—์„œ๋Š” ์•”๋ฌต์ ์ธ ๋ณ€ํ™˜ ๋ฐฉ๋ฒ•๊ณผ ๋ช…์‹œ์ ์ธ ๋ณ€ํ™˜ ๋ฐฉ๋ฒ•์„ ๋ชจ๋‘ ์ œ๊ณตํ•œ๋‹ค.


์•”๋ฌต์ ์ธ ํƒ€์ž… ๋ณ€ํ™˜

๊ฐœ๋ฐœ์ž๊ฐ€ ๋”ฐ๋กœ ๋ช…์‹œํ•˜์ง€ ์•Š์•„๋„ ์ฝ”๋“œ ์ปจ๋ฒค์…˜์— ๋”ฐ๋ผ ์ž๋™์œผ๋กœ ๋ณ€ํ™˜์ด ๋  ์ˆ˜ ์žˆ๋Š”๋ฐ,
์˜ˆ๋ฅผ ๋“ค์–ด "true"๋ผ๋Š” ๋ฌธ์ž์—ด์„ ์ œ๊ณตํ•ด ์ค„ ๋•Œ ๋งค๊ฐœ๋ณ€์ˆ˜๋ฅผ boolean value๋กœ ๋ฐ›๋Š”๋‹ค๋ฉด boolean ํƒ€์ž…์˜ true ๊ฐ’์œผ๋กœ ๋Œ€์ž…๋œ๋‹ค.

๊ทธ ๋ฐ–์—๋„ ๋งŽ์€ ๋ฐ์ดํ„ฐ๋“ค์— ๋Œ€ํ•ด์„œ ์•”๋ฌต์ ์œผ๋กœ ํƒ€์ž… ๋ณ€ํ™˜์„ ์ œ๊ณตํ•˜๋Š”๋ฐ ๋‹ค์Œ ๋งํฌ๋ฅผ ์ฐธ๊ณ ํ•˜๋ฉด ๋œ๋‹ค.

JUnit 5 User Guide



๋ช…์‹œ์ ์ธ ํƒ€์ž… ๋ณ€ํ™˜

์ง์ ‘ ๋งŒ๋“  ๊ฐ์ฒด(์ปค์Šคํ…€ ํ•œ ํƒ€์ž…)๋กœ ๋ณ€ํ™˜์„ ํ•˜๋ ค๋ฉด ์–ด๋–ป๊ฒŒ ํ•ด์•ผ ํ• ๊นŒ โ“


SimpleArgumentConverter์„ ๊ตฌํ˜„ํ•ด์„œ ์ ์šฉ

  • ๋ณดํ†ต ํ•˜๋‚˜์˜ ์ธ์ž ๊ฐ’์„ ๋ณ€ํ™˜ํ•˜๊ณ ์ž ํ•  ๋•Œ ์‚ฌ์šฉํ•˜๋ฉฐ static inner class ๋˜๋Š” ๋‹ค๋ฅธ public class์˜ static ํด๋ž˜์Šค

  • ๋งค๊ฐœ๋ณ€์ˆ˜๋ฅผ ์ „๋‹ฌ๋ฐ›๋Š” ๋ฉ”์„œ๋“œ์—์„œ๋Š” ๋‚ด๊ฐ€ ๋ณ€ํ™˜ ๋ฐ›๊ณ ์ž ํ•˜๋Š” ๋งค๊ฐœ๋ณ€์ˆ˜์— @ConvertWith์–ด๋…ธํ…Œ์ด์…˜์„ ๋ถ™์—ฌ์„œ ์‚ฌ์šฉ

@DisplayName("์Šคํ„ฐ๋”” ๋งŒ๋“ค๊ธฐ")
@ParameterizedTest(name = "{index} {displayName} ๊ณผ๋ชฉ:{arguments}")
@ValueSource(ints = {1,2,3,4,5})
void create_new_study_again(@ConvertWith(StudyConverter.class)Study study) {
    System.out.println("study = " + study.toString());
}

static class StudyConverter extends SimpleArgumentConverter{

    @Override
    protected Object convert(Object o, Class<?> aClass) throws ArgumentConversionException {
        assertEquals(Study.class, aClass, "Can Only convert to Study");
        return new Study(Integer.parseInt(o.toString()));
    }
}



ArgumentsAccessor์„ ๋งค๊ฐœ๋ณ€์ˆ˜๋กœ ๋ฐ›์•„ ์‚ฌ์šฉ

  • ํ•˜๋‚˜ ์ด์ƒ์˜ ์ธ์ž ๊ฐ’์„ ๋ฐ›๊ณ  ์‹ถ์„ ๋•Œ ํ•ด๋‹น ๋งค๊ฐœ๋ณ€์ˆ˜๋ฅผ ๋ฐ›์•„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

  • ๋งค๊ฐœ๋ณ€์ˆ˜๋กœ ๋ฐ›์€ accessor๋ฅผ ์ด์šฉํ•ด ์ธ๋ฑ์Šค๋ฅผ ํ™œ์šฉํ•œ getter๋กœ ๊ฐ’์„ ๊บผ๋‚ด ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

@DisplayName("์Šคํ„ฐ๋”” ๋งŒ๋“ค๊ธฐ")
@ParameterizedTest(name = "{index} {displayName} ๊ณผ๋ชฉ:{arguments}")
@CsvSource({"10,'์ˆ˜ํ•™'", "20,์Šคํ”„๋ง"})
void create_new_study_again_with_csvsource(ArgumentsAccessor accessor) {
    System.out.println(accessor.getInteger(0));
    System.out.println(accessor.getString(1));

}



ArgumentsAggregator๋ฅผ ์‚ฌ์šฉํ•ด ์ปค์Šคํ…€ ํƒ€์ž… ๋ณ€ํ™˜

  • accessor๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š๊ณ  ํ•ด๋‹น ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ๊ตฌํ˜„ํ•ด ๊ฐ์ฒด๋ฅผ ์‚ฌ์ „์— ์ƒ์„ฑํ•ด์„œ ์ „๋‹ฌํ•  ์ˆ˜๋„ ์žˆ๋‹ค.

  • ์ฝ”๋“œ ๋‚ด๋ถ€์ ์œผ๋กœ๋Š” accessor๋ฅผ ์ด์šฉํ•ด ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑ์„ Aggregator์—์„œ ํ•ด์ฃผ๋Š” ๊ฒƒ๋ฟ์ด๋‹ค.

  • ๋งค๊ฐœ๋ณ€์ˆ˜๋กœ ๋ฐ›์„ ๋ถ€๋ถ„์—์„œ @AggregateWith ์–ด๋…ธํ…Œ์ด์…˜์„ ์‚ฌ์šฉํ•ด ํ•ด๋‹น Aggregator๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค.

@DisplayName("์Šคํ„ฐ๋”” ๋งŒ๋“ค๊ธฐ")
@ParameterizedTest(name = "{index} {displayName} ๊ณผ๋ชฉ:{arguments}")
@CsvSource({"10,'์ˆ˜ํ•™'", "20,์Šคํ”„๋ง"})
void create_new_study_again_with_aggregator(@AggregateWith(StudyAggregator.class) Study study) {
    System.out.println("study = " + study);
}

static class StudyAggregator implements ArgumentsAggregator {
    @Override
    public Object aggregateArguments(ArgumentsAccessor accessor, ParameterContext parameterContext) throws ArgumentsAggregationException {
        return new Study(accessor.getString(1), accessor.getInteger(0));
    }

}



ํ…Œ์ŠคํŠธ ์ธ์Šคํ„ด์Šค

JUnit์€ ํ…Œ์ŠคํŠธ ๋ฉ”์„œ๋“œ ๋ณ„๋กœ ํ…Œ์ŠคํŠธ ์ธ์Šคํ„ด์Šค๋ฅผ ์ƒˆ๋กœ ๋งŒ๋“ค๋ฉฐ ์ด๊ฒƒ์ด ๊ธฐ๋ณธ ์ „๋žต์ด๋‹ค.

์ด์ฒ˜๋Ÿผ ๊ฐ๊ฐ์˜ ๋ฉ”์„œ๋“œ๋ฅผ ๋…๋ฆฝ์ ์œผ๋กœ ์‹คํ–‰ํ•  ๊ฒฝ์šฐ ๋‹ค๋ฅธ ๋ฉ”์„œ๋“œ๋กœ๋ถ€ํ„ฐ ์˜ํ–ฅ์„ ๋ฐ›์ง€ ์•Š๊ธฐ์— ์˜ˆ์ƒ์น˜ ๋ชปํ•œ ๋‹ค๋ฅธ ํ…Œ์ŠคํŠธ๋กœ๋ถ€ํ„ฐ์˜ ์˜ํ–ฅ์„ ๋ฐ›์„ ์ผ์ด ์ค„์–ด๋“ ๋‹ค.
ํ•˜์ง€๋งŒ, JUnit5์—์„œ๋Š” ์ƒํ™ฉ์— ๋”ฐ๋ผ ์ด๋Ÿฌํ•œ ์ „๋žต์„ ๋ฐ”๊ฟ”์ค„ ์ˆ˜๋„ ์žˆ๋‹ค.


@TestInstance(Lifecycle.PER_CLASS)

  • ํ…Œ์ŠคํŠธ๋ฅผ ํด๋ž˜์Šค๋‹น ์ธ์Šคํ„ด์Šค๋ฅผ ํ•˜๋‚˜๋งŒ ๋งŒ๋“ค์–ด์„œ ์‚ฌ์šฉํ•œ๋‹ค.

  • ๊ฒฝ์šฐ์— ๋”ฐ๋ผ ํ…Œ์ŠคํŠธ ๊ฐ„์— ๊ณต์œ ํ•˜๋Š” ๋ชจ๋“  ์ƒํƒœ๋ฅผ @BeforeEach ๋˜๋Š” @AfterEach์—์„œ ์ดˆ๊ธฐํ™”ํ•  ํ•„์š”๊ฐ€ ์žˆ๋‹ค.

  • @BeforeAll๊ณผ @AfterAll์„ ์ธ์Šคํ„ด์Šค ๋ฉ”์„œ๋“œ ๋˜๋Š” ์ธํ„ฐํŽ˜์ด์Šค์— ์ •์˜ํ•œ default ๋ฉ”์„œ๋“œ๋กœ ์ •์˜ํ•  ์ˆ˜ ์žˆ๋‹ค.

@TestInstance(TestInstance.Lifecycle.PER_CLASS)
class StudyTest {
    
         @BeforeAll
	  void beforeAll() {
	      System.out.println("beforeAll");
	  }
	  
	  @AfterAll
	  void afterAll() {
	      System.out.println("afterAll");
	  }
		...
}

@BeforeAll, @AfterAll ์–ด๋…ธํ…Œ์ด์…˜์€ ํ…Œ์ŠคํŠธ ์ธ์Šคํ„ด์Šค๊ฐ€ PER_CLASS๋กœ ํด๋ž˜์Šค๋‹น ํ•˜๋‚˜์˜ ์ธ์Šคํ„ด์Šค๋งŒ ์ƒ์„ฑํ•˜๋„๋ก ๋˜๋ฉด static ํ‚ค์›Œ๋“œ๋ฅผ ์ œ๊ฑฐํ•˜์—ฌ ์ธ์Šคํ„ด์Šค ๋ฉ”์„œ๋“œ๋กœ ์„ ์–ธํ•  ์ˆ˜ ์žˆ๋‹ค.



ํ…Œ์ŠคํŠธ ์ˆœ์„œ

ํ…Œ์ŠคํŠธ ๋ฉ”์„œ๋“œ๋Š” ํŠน์ •ํ•œ ์ˆœ์„œ์— ์˜ํ•ด ์‹คํ–‰์ด ๋˜์ง€๋งŒ ๊ทธ ์ˆœ์„œ๊ฐ€ ์–ด๋–ป๊ฒŒ ์ •ํ•ด์ง€๋Š”์ง€์— ๋Œ€ํ•ด์„œ๋Š” ์˜๋„์ ์œผ๋กœ ๋ฐํžˆ๊ณ  ์žˆ์ง€ ์•Š๋Š”๋‹ค. ๊ทธ ์ด์œ ๋Š” ํ•˜๋‚˜์˜ ๋‹จ์œ„(ํ…Œ์ŠคํŠธ)๋Š” ๋…๋ฆฝ์ ์œผ๋กœ ์‹คํ–‰๋˜๋ฉฐ ๋‹ค๋ฅธ ๋ฉ”์„œ๋“œ์— ์˜ํ–ฅ์„ ์ฃผ๋ฉด ์•ˆ ๋œ๋‹ค.


ํ•˜์ง€๋งŒ, ํŠน์ • ์ˆœ์„œ๋Œ€๋กœ ํ…Œ์ŠคํŠธ๋ฅผ ์‹คํ–‰ํ•ด์•ผ ํ•˜๋Š” ๊ฒฝ์šฐ(Functional Test, Acceptance Test...)๊ฐ€ ์žˆ๋‹ค๋ฉด ์–ด๋…ธํ…Œ์ด์…˜์„ ํ†ตํ•ด ์ด ํ…Œ์ŠคํŠธ ๋ฉ”์„œ๋“œ์˜ ์‹คํ–‰ ์ˆœ์„œ๋ฅผ ์ œ์–ดํ•  ์ˆ˜ ์žˆ๋‹ค.


@MethodOrderer

  • ๊ธฐ๋ณธ ๊ตฌํ˜„์ฒด
    • MethodOrderer.OrderAnnotation.class
    • MethodOrderer.Alphanumeric.class
    • MethodOrderer.Random.class

โœ… @TestInstance(Lifecycle.PER_CLASS)์™€ ํ•จ๊ป˜ ์‚ฌ์šฉ์„ ํ•˜์ง€ ์•Š์•„๋„ ๋œ๋‹ค.

ํ…Œ์ŠคํŠธ ์ˆœ์„œ ์–ด๋…ธํ…Œ์ด์…˜๋“ค์€ ์ž‘๋™์„ ํ•œ๋‹ค. ๋‹ค๋งŒ, ํ•ด๋‹น ์• ๋…ธํ…Œ์ด์…˜์œผ๋กœ ํด๋ž˜์Šค ๋‹จ์œ„๋กœ ํ…Œ์ŠคํŠธ๊ฐ€ ์ˆ˜ํ–‰๋œ๋‹ค๋ฉด, ์ƒํƒœ๊ฐ€ ๊ณต์œ ๋˜๋Š” stateful ํ•œ ํ…Œ์ŠคํŠธ๋ฅผ ํด๋ž˜์Šค ๋‹จ์œ„๋กœ ์‹คํ–‰ํ•  ๋•Œ ์œ ์šฉํ•˜๋‹ค.



@TestInstance(TestInstance.Lifecycle.PER_CLASS)
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
class StudyTest {
    
    @Order(0)
    @DisplayName("๋ฐ˜๋ณตํ…Œ์ŠคํŠธ")
    @RepeatedTest(value = 10, name = "{displayName} {currentRepetition}/{totalRepetitions}")
    void repeatTest(RepetitionInfo repetitionInfo) {
        System.out.println(this);
        System.out.println("repetitionInfo.getCurrentRepetition() = " + repetitionInfo.getCurrentRepetition());
        System.out.println("repetitionInfo.getTotalRepetitions() = " + repetitionInfo.getTotalRepetitions());
    }

    @Order(1)
    @DisplayName("์Šคํ„ฐ๋”” ๋งŒ๋“ค๊ธฐ 1")
    @ParameterizedTest(name = "{index} {displayName} ๊ณผ๋ชฉ:{arguments}")
    @ValueSource(strings = {"์ˆ˜ํ•™", "์˜์–ด", "๊ตญ์–ด", "์ฒด์œก"})
    void create_new_study(String input) {
        System.out.println(this);
        System.out.println("input = " + input);
    }

    @Order(2)
    @DisplayName("์Šคํ„ฐ๋”” ๋งŒ๋“ค๊ธฐ 2")
    @ParameterizedTest(name = "{index} {displayName} ๊ณผ๋ชฉ:{arguments}")
    @ValueSource(ints = {1,2,3,4,5})
    void create_new_study_again(@ConvertWith(StudyConverter.class)Study study) {
        System.out.println(this);
        System.out.println("study = " + study.toString());
    }
}



  • OrderAnnotation ๊ธฐ์ค€์œผ๋กœ ์‹คํ–‰์ด ๋œ๋‹ค.
  • ๊ฐ๊ฐ์˜ ํ…Œ์ŠคํŠธ ๋ฉ”์„œ๋“œ๋“ค์ด @Order๊ฐ€ ์žˆ๋Š”๋ฐ ์•ˆ์— ์ž‘์„ฑํ•œ value ๊ฐ’์— ๋”ฐ๋ผ ์ˆœ์„œ๋Œ€๋กœ ์ˆ˜ํ–‰๋œ๋‹ค
  • ๋งŒ์•ฝ @Order ๋‚ด๋ถ€์˜ ๊ฐ’์ด ๊ฐ™์„ ๊ฒฝ์šฐ ์ž์ฒด์ ์ธ ์ˆœ์„œ์— ๋”ฐ๋ผ ์ˆ˜ํ–‰๋œ๋‹ค.



junit-platform.properties

JUnit์€ ์„ค์ • ํŒŒ์ผ(properties)์„ ์ด์šฉํ•ด ํด๋ž˜์Šค ํŒจ์Šค ๋ฃจํŠธ(src/test/resources/)์— ๋„ฃ์–ด๋‘๋ฉด ์ ์šฉ๋œ๋‹ค.

// ํ…Œ์ŠคํŠธ ์ธ์Šคํ„ด์Šค ๋ผ์ดํ”„ ์‚ฌ์ดํด ์„ค์ •
junit.jupiter.testinstance.lifecycle-default=per_class

// ํ™•์žฅํŒฉ ์ž๋™ ๊ฐ์ง€ ๊ธฐ๋Šฅ
junit.jupiter.extensions.autodetection.enabled=true

// @Disabled ๋ฌด์‹œํ•˜๊ณ  ์‹คํ–‰ํ•˜๊ธฐ
junit.jupiter.conditions.deactivate=org.junit.*DisabledCondition

// ํ…Œ์ŠคํŠธ ์ด๋ฆ„ ํ‘œ๊ธฐ ์ „๋žต ์„ค์ •
junit.jupiter.displayname.generator.default=org.junit.jupiter.api.DisplayNameGenerator$ReplaceUnderscores

ํ…Œ์ŠคํŠธ ํด๋ž˜์Šค๊ฐ€ ์ˆ˜์‹ญ, ์ˆ˜๋ฐฑ ๊ฐœ๊ฐ€ ๋˜๋Š” ๊ฒฝ์šฐ ์™ธ๋ถ€ ์„ค์ • ํŒŒ์ผ์„ ํ†ตํ•ด ํ†ตํ•ฉํ•ด์„œ ๊ด€๋ฆฌํ•ด ์ค„ ์ˆ˜ ์žˆ๋‹ค.