- Java 8 ์ด์์ด ํ์ํ๋ค.
- ๋์ฒด์ ๋ก TestNg, Spock๋ฑ ๋ง์ง๋ง JUnit๋ง ์์๋ ๋ฌธ์ ์๋ค.
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
๊ตฌํ์ฒด์ด๋ค.
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");
}
}
- ํด๋น ๋ฉ์๋๋ฅผ ํ ์คํธ ๋์์ผ๋ก ์ง์ ํ๋ค.
- ๋ชจ๋ ํ
์คํธ ์์ ์ ์ ์ํ๋๋ ๋ก์ง์ ๋ถ๋ ์ด๋
ธํ
์ด์
์ผ๋ก
static
์ ๋ถ์ฌ์ค์ผ ํ๋ฉฐ, ์ ๊ทผ ์ ์ด์๋default
์ด์์ด์ด์ผ ํ๋ค.
- ๋ชจ๋ ํ
์คํธ ์ข
๋ฃ ํ์ ์ํ๋๋ ๋ก์ง์ ๋ถ๋ ์ด๋
ธํ
์ด์
์ผ๋ก
static
์ ๋ถ์ฌ์ค์ผ ํ๋ฉฐ, ์ ๊ทผ ์ ์ด์๋default
์ด์์ด์ด์ผ ํ๋ค.
- ๋ชจ๋
@Test
์ด๋ ธํ ์ด์ ์ด ๋ถ์ ํ ์คํธ ๋์ ๋ฉ์๋ ์ํ ์ ๋ง๋ค ์ํ๋๋ค.
- ๋ชจ๋
@Test
์ด๋ ธํ ์ด์ ์ด ๋ถ์ ํ ์คํธ ๋์ ๋ฉ์๋ ์ํ ์ข ๋ฃ ์๋ง๋ค ์ํ๋๋ค.
- ํด๋น ์ด๋ ธํ ์ด์ ์ด ๋ถ์ ๋ฉ์๋๋ ํ ์คํธ ์ ์ธ ๋์์ผ๋ก ํ ์คํธ๋ฅผ ์ํํ์ง ์๋๋ค.
-
ํ ์คํธ ์ด๋ฆ์ ๋ณด๊ธฐ ์ฝ๊ฒ ํํํ๋ ์ด๋ ธํ ์ด์
-
์ฐ์ ์์๋
@DisplayNameGeneration
๋ณด๋ค ๋๋ค. -
์ด๋ชจ์ง๊ฐ์ ์ด๋ชจํฐ์ฝ๋ ์ง์์ ํ๋ค.
-
ํด๋น ์ ๋ ธํ ์ด์ ์ญ์ ํด๋์ค์ ๋ฉ์๋ ๋ชจ๋ ๋ถ์ฌ์ค ์ ์๋ค.
-
@DisplayName("ํ
์คํธ ํด๋์ค")
public class TestClass {
...
@DisplayName("ํ์ ์์ฑ ํ
์คํธ")
@Test
void create_account_test(){
...
}
}
๊ตฌํํ ๊ธฐ๋ฅ์ด ์์ธกํ ๋๋ก ๋์ค๋์ง ํ์ธํ๊ธฐ ์ํด์๋ ์ด๋ฅผ ๊ฒ์ฆํด ์ค ๊ธฐ๋ฅ์ด ํ์ํ๋ค.
org.junit.jupiter.api.Assertions
์์๋ ๊ฒ์ฆ์ ์ํ ๋ค์ํ ๋ฉ์๋๋ฅผ ์ ๊ณตํด ์ค๋ค.
- ๊ธฐ๋ํ ๊ฐ(expected)์ด ์ค์ ๊ฐ(actual)๊ณผ ๊ฐ์์ง ํ์ธํ๋ ๋ฉ์๋
@DisplayName("์คํฐ๋ ๋ง๋ค๊ธฐ ")
@Test
void create_new_study() {
Study study = new Study();
assertEquals(StudyStatus.DRAFT, study.getStatus(),()-> "์คํฐ๋๋ฅผ ์ฒ์ ๋ง๋ค๋ฉด DRAFT ์ํ๋ค. ");
}
-
assertEquals
์์๋ ์ธ ๋ฒ์งธ ํ๋ผ๋ฏธํฐ๋ก ๋ฉ์์ง๋ฅผ ์ค ์ ์๋ค.-
ํด๋น ํ ์คํธ๊ฐ ํต๊ณผํ์ง ๋ชปํ์ ๊ฒฝ์ฐ ์ถ๋ ฅ๋๋ค.
-
์ด๋
Supplier<_String_>
ํ์ ์ ์ธ์คํด์ค๋ฅผ ๋๋ค๋ก ์ ๊ณตํ ์๋ ์๋๋ฐ, ๋ณต์กํ ๋ฉ์์ง๋ฅผ ์์ฑํด์ผ ํ๋ ๊ฒฝ์ฐ ๋๋ค๋ฅผ ์ฌ์ฉํ๋ฉด ์คํจํ ๊ฒฝ์ฐ์๋ง ํด๋น ๋ฉ์์ง๋ฅผ ๋ง๋ค ์ ์์ด ํจ์จ์ ์ด๋ค.
-
- ๊ฒฐ๊ณผ ๊ฐ(actual)์ด null ์ธ์ง ์๋์ง ํ์ธํ๋ ๋ฉ์๋
@DisplayName("์คํฐ๋ ๋ง๋ค๊ธฐ ")
@Test
void create_new_study() {
Study study = new Study();
assertNotNull(study);
}
- ๋ค์ ์กฐ๊ฑด์ด ์ฐธ์ธ์ง ํ์ธํ๋ ๋ฉ์๋
@DisplayName("์คํฐ๋ ๋ง๋ค๊ธฐ ")
@Test
void create_new_study() {
Study study = new Study();
assertTrue(study.getStatus().equals(StudyStatus.DRAFT));
}
- ๋ชจ๋ ๊ตฌ๋ฌธ ํ์ธ ๋ฉ์๋
@DisplayName("์คํฐ๋ ๋ง๋ค๊ธฐ ")
@Test
void create_new_study() {
Study study = new Study();
assertNotNull(study);
assertAll(
()->assertEquals(StudyStatus.DRAFT, study.getStatus(),()-> "์คํฐ๋๋ฅผ ์ฒ์ ๋ง๋ค๋ฉด DRAFT ์ํ๋ค. "),
()->assertTrue(study.getLimit() > 0, ()-> "์คํฐ๋ ์ต๋ ์ฐธ์ ๊ฐ๋ฅ ์ธ์์ 0๋ช
์ด์์ด์ด์ผ ํ๋ค. ")
);
}
-
์์ธ ๋ฐ์ ํ์ธ ๋ฉ์๋
์์ธ ๊ฒ์ฆ ํ ํด๋น ์์ธ๋ฅผ ๋ฐํ
ํด์ฃผ๊ธฐ์ ์์ธ ๋ฉ์์ง ๊ฒ์ฆ์ด ๊ฐ๋ฅํ๋ค.
@DisplayName("์คํฐ๋ ๋ง๋ค๊ธฐ ")
@Test
void create_new_study() {
IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, () -> new Study(-1));
assertEquals(exception.getMessage(), "limit ์ 0๋ณด๋ค ์ปค์ผํ๋ค.");
}
- ํน์ ์๊ฐ ๋ด์ ์คํ ์๋ฃ๋๋์ง ํ์ธํ๋ ๋ฉ์๋
@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, ํ๊ฒฝ ๋ณ์, ์์คํ ๋ณ์์ ๋ฐ๋ผ ํ ์คํธ ์คํ ๊ฒฐ์
-
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: ๋ชจ๋ ๋ณ, ๋จ์/ํตํฉ ๊ตฌ๋ถ, ๊ธฐํ ์กฐ๊ฑด)
- ํ๋์ ํ ์คํธ ๋ฉ์๋์ ์ฌ๋ฌ ํ๊ทธ๋ฅผ ์ฌ์ฉํ ์๋ ์๋ค.
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๋ผ๋ ์์์ ์ด๋ ธํ ์ด์ ์ ๋ง๋ค์ด์ ๋ฉํ ์ด๋ ธํ ์ด์ ์ ์ ์ํด ๋ณด์.
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Test
@Tag("fast")
public @interface FastTest { }
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Test
@Tag("slow")
public @interface SlowTest { }
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์์๋ ์ด๋ฌํ ํ ์คํธ ๋ฐ๋ณต์ ์ํ ์ด๋ ธํ ์ด์ ์ ์ ๊ณตํ๋ค.
- ์์ฑ์ ํตํด ๋ฐ๋ณต ํ์์ ๋ฐ๋ณต ํ ์คํธ ์ด๋ฆ์ ์ค์ ํ ์ ์๋ค.
@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(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
์ ๋ํด ์์๋ดค๋๋ฐ ์ธ์ ๊ฐ๋ค์ ์ ๊ณตํด ์ฃผ๋ ์ด๋
ธํ
์ด์
์ ๋ ์๋ค.
- Null๊ณผ ๊ณต๋ฐฑ๋ฌธ์๋ฅผ ์ ๊ณตํด ์ฃผ๋ ์ด๋
ธํ
์ด์
์ผ๋ก ๊ฐ๊ฐ ์ ๊ณตํด ์ค ์๋ ์๊ณ ,
@NullAndEmptySource
๋ฅผ ํตํด ๋ ๋ค ์ ๊ณตํด ์ค ์๋ ์๋ค.
- 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
- ํน์ ๋ฉ์๋๋ฅผ ๋ง๋ค์ด์ ์ธ์ ๊ฐ์ ์ ๋ฌ๋ฐ๋๋ค.
@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)
);
}
- 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);
}
- ํ์ผ์ ์ฝ์ด์์ ์ธ์๋ก ์ ๊ณตํ๋ ์ด๋ ธํ ์ด์
- 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 ๊ฐ์ผ๋ก ๋์
๋๋ค.
๊ทธ ๋ฐ์๋ ๋ง์ ๋ฐ์ดํฐ๋ค์ ๋ํด์ ์๋ฌต์ ์ผ๋ก ํ์ ๋ณํ์ ์ ๊ณตํ๋๋ฐ ๋ค์ ๋งํฌ๋ฅผ ์ฐธ๊ณ ํ๋ฉด ๋๋ค.
์ง์ ๋ง๋ ๊ฐ์ฒด(์ปค์คํ ํ ํ์ )๋ก ๋ณํ์ ํ๋ ค๋ฉด ์ด๋ป๊ฒ ํด์ผ ํ ๊น โ
-
๋ณดํต ํ๋์ ์ธ์ ๊ฐ์ ๋ณํํ๊ณ ์ ํ ๋ ์ฌ์ฉํ๋ฉฐ 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()));
}
}
-
ํ๋ ์ด์์ ์ธ์ ๊ฐ์ ๋ฐ๊ณ ์ถ์ ๋ ํด๋น ๋งค๊ฐ๋ณ์๋ฅผ ๋ฐ์ ์ฌ์ฉํ ์ ์๋ค.
-
๋งค๊ฐ๋ณ์๋ก ๋ฐ์ 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));
}
-
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์์๋ ์ํฉ์ ๋ฐ๋ผ ์ด๋ฌํ ์ ๋ต์ ๋ฐ๊ฟ์ค ์๋ ์๋ค.
-
ํ ์คํธ๋ฅผ ํด๋์ค๋น ์ธ์คํด์ค๋ฅผ ํ๋๋ง ๋ง๋ค์ด์ ์ฌ์ฉํ๋ค.
-
๊ฒฝ์ฐ์ ๋ฐ๋ผ ํ ์คํธ ๊ฐ์ ๊ณต์ ํ๋ ๋ชจ๋ ์ํ๋ฅผ
@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.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์ ์ค์ ํ์ผ(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
ํ ์คํธ ํด๋์ค๊ฐ ์์ญ, ์๋ฐฑ ๊ฐ๊ฐ ๋๋ ๊ฒฝ์ฐ ์ธ๋ถ ์ค์ ํ์ผ์ ํตํด ํตํฉํด์ ๊ด๋ฆฌํด ์ค ์ ์๋ค.