๋ชฉ์ฐจ
- JUnit5๋?
- JUnit5 ๊ตฌ์ฑ
- JUnit5 ์์ํ๊ธฐ
- JUnit5์ ์ด๋ ธํ ์ด์ ๋ค
- JUnit5 ํ ์คํธ ์ด๋ฆ ํ์ํ๊ธฐ
- JUnit5 Assertion
- ์กฐ๊ฑด์ ๋ฐ๋ผ ํ ์คํธ ์คํํ๊ธฐ
- ํ๊น ๊ณผ ํํฐ๋ง
- ํ ์คํธ ๋ฐ๋ณตํ๊ธฐ
- ํ ์คํธ ์ธ์คํด์ค
- ํ ์คํธ ์์
1. JUnit5๋?
Junit๋ ํ
์คํ
๊ธฐ๋ฐ ํ๋ ์์ํฌ๋ก์จ ์๋ฐ ๊ฐ๋ฐ์๊ฐ ๊ฐ์ฅ ๋ง์ด ์ฌ์ฉํ๋ ํ๋ ์์ํฌ์
๋๋ค.
ํ
์คํธ ์ฃผ๋ ๊ฐ๋ฐ(Test Driven Development, TDD)์ ์ํด ์ฌ์ฉํฉ๋๋ค.
- ์๊ตฌ์ฌํญ์ ๊ฒ์ฆํ๋ ํ ์คํธ ์ผ์ด์ค ์์ฑ
- ํ ์คํธ ํต๊ณผ๋ฅผ ์ํ ์ฝ๋ ์์ฑ
- ์ดํ ๋ฆฌํฉํ ๋งํ์ฌ ์ค์ ๊ฐ๋ฐ ์ฝ๋์ ์ ์ฉ
2. JUnit5 ๊ตฌ์ฑ
JUnit5๋ Java8๋ฒ์ ์ด์๋ถํฐ ์ฌ์ฉ์ด ๊ฐ๋ฅํ๋ฉฐ Platform, Jupiter, Vintage ์ด ์ธ ๊ฐ์ง๊ฐ ๊ฒฐํฉํ ํํ๋ก ์ด๋ฃจ์ด์ ธ ์์ต๋๋ค.
JUnit Platform
- JVM์์ ํ ์คํธ ํ๋ ์์ํฌ๋ฅผ ์คํํ๋ ๋ฐ์ฒ์ TestEngine API ์ ๊ณต
JUnit Jupiter
- TestEngine API์ ๊ตฌํ์ฒด๋ก JUnit5์์ ์ ๊ณต
JUnit Vintage
- TestEngine API์ ๊ตฌํ์ฒด๋ก JUnit3, JUnit4์์ ์ ๊ณต
- ํ์ ํธํ์ฑ์ ์ํด JUnit3, JUnit4 ๊ธฐ๋ฐ์ ํ๋ซํผ์ TestEngine ์ ๊ณต
3. JUnit5 ์์ํ๊ธฐ
2.2+ ๋ฒ์ ์ด์์ ์คํ๋ง ๋ถํธ ํ๋ก์ ํธ๋ฅผ ๋ง๋ ๋ค๋ฉด ๊ธฐ๋ณธ์ผ๋ก JUnit5 ์์กด์ฑ์ด ์ถ๊ฐ๋๊ธฐ ๋๋ฌธ์ ๋ฐ๋ก ์ค์ ํ ํ์๋ ์์ต๋๋ค.
๋ง์ฝ ์คํ๋ง ๋ถํธ๊ฐ ์๋๋ผ๋ฉด ์๋์ ๊ฐ์ด ์ง์ ์์กด์ฑ์ ์ถ๊ฐํฉ๋๋ค.
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<version>5.5.2</version>
<scope>test</scope>
</dependency>
4. JUnit5 ์ด๋ ธํ ์ด์ ๋ค
@Test: ํ
์คํธ Method์์ ์ ์ธํฉ๋๋ค.
@ParameterizedTest: ๋งค๊ฐ๋ณ์๋ฅผ ๋ฐ๋ ํ
์คํธ๋ฅผ ์์ฑํฉ๋๋ค.
@RepeatedTest: ๋ฐ๋ณต๋๋ ํ
์คํธ๋ฅผ ์์ฑํฉ๋๋ค.
@TestFactory: @Test๋ก ์ ์ธ๋ ์ ์ ํ
์คํธ๊ฐ ์๋ ๋์ ์ผ๋ก ํ
์คํธ๋ฅผ ์ฌ์ฉํฉ๋๋ค.
@TestInstance: ํ
์คํธ ํด๋์ค์ ์๋ช
์ฃผ๊ธฐ๋ฅผ ์ค์ ํฉ๋๋ค.
@TestTemplate: ๊ณต๊ธ์์ ์ํด ์ฌ๋ฌ ๋ฒ ํธ์ถ๋ ์ ์๋๋ก ์ค๊ณ๋ ํ
์คํธ ์ผ์ด์ค ํ
ํ๋ฆฟ์์ ๋ํ๋
๋๋ค.
@TestMethodOrder: ํ
์คํธ ๋ฉ์๋ ์คํ ์์๋ฅผ ๊ตฌ์ฑํ๋๋ฐ ์ฌ์ฉํฉ๋๋ค.
@DisplayName: ํ
์คํธ ํด๋์ค ๋๋ ํ
์คํธ ๋ฉ์๋์ ์ด๋ฆ์ ์ ์ํ ๋ ์ฌ์ฉํฉ๋๋ค.
@DisplayNameGeneration: ํ
์คํธ ํด๋์ค์ ์ ์ํ๋ฉฐ, ํ
์คํธ ๋ฉ์๋์ ์ด๋ฆ์ ์นํํด์ค๋๋ค.
@BeforeEach: ๊ฐ๊ฐ์ ํ
์คํธ๋ฅผ ์คํํ๊ธฐ ์ ์ ๋งค๋ฒ ์ฐ์ ์ ์ผ๋ก ํ
์คํธ๋ฉ๋๋ค.
@AfterEach: ๊ฐ๊ฐ์ ํ
์คํธ๋ฅผ ์คํํ ํ์ ๋งค๋ฒ ํ
์คํธ๋ฉ๋๋ค.
@BeforeAll: ๋ชจ๋ ํ
์คํธ๋ฅผ ์คํํ๊ธฐ ์ ๋ฑ ํ๋ฒ๋ง ํธ์ถ๋ฉ๋๋ค.
๋ฐ๋์ static method๋ก ์ ์ธํด์ผ ํฉ๋๋ค.
private ๋ถ๊ฐ, default ๊ฐ๋ฅ, return type ๋ถ๊ฐ๋ฅ ์ค์ง void๋ง ๊ฐ๋ฅํฉ๋๋ค.
@AfterAll: ๋ชจ๋ ํ
์คํธ๋ฅผ ์คํํ ํ ๋ฑ ํ๋ฒ๋ง ํธ์ถ๋ฉ๋๋ค.
๋ฐ๋์ static method๋ก ์ ์ธํด์ผ ํฉ๋๋ค.
private ๋ถ๊ฐ, default ๊ฐ๋ฅ, return type ๋ถ๊ฐ๋ฅ ์ค์ง void๋ง ๊ฐ๋ฅํฉ๋๋ค.
@Nested: ํด๋์ค๊ฐ ์ ์ ์ด ์๋๋ผ ์ค์ฒฉ ํ
์คํธ ํด๋์ค์์ ๋ํ๋
๋๋ค.
@Tag: ํด๋์ค ๋๋ ๋ฉ์๋ ๋ ๋ฒจ์์ ํ๊ทธ๋ฅผ ์ ์ธํ ๋ ์ฌ์ฉ๋๋ฉฐ, Mavan์ ์ฌ์ฉํ ๊ฒฝ์ฐ ํ๊ทธ ์ค์ ์ ํตํด ์ํ๋ ํ๊ทธ๋ง ์คํํ๊ฑฐ๋ ์ ์ธ์ํฌ ์ ์์ต๋๋ค.
@Disabled: ์ด ํด๋์ค๋ ํ
์คํธ๋ฅผ ์ฌ์ฉํ์ง ์์ต๋๋ค.(์คํ๋์ง ์์ต๋๋ค.)
@Timeout: ํ
์คํธ ์คํ ์๊ฐ์ ์ ์ธํ ํ, ์๊ฐ๋ด์ ํ
์คํธ๊ฐ ์ข
๋ฃ๋์ง ์์ผ๋ฉด ์คํจ๋๋๋ก ํฉ๋๋ค.
@ExtendWith: ํ์ฅ์ ์ ์ธ์ ์ผ๋ก ๋ฑ๋กํ ๋ ์ฌ์ฉํฉ๋๋ค.
@RegisterExtension: ํ๋๋ฅผ ํตํด ํ๋ก๊ทธ๋๋ฐ ๋ฐฉ์์ผ๋ก ํ์ฅ์ ๋ฑ๋กํ ๋ ์ฌ์ฉํฉ๋๋ค.
@TempDir: ํ๋ ์ฃผ์
๋๋ ๋งค๊ฐ๋ณ์ ์ฃผ์
์ ํตํด ์์ ๋๋ ํ ๋ฆฌ๋ฅผ ์ ๊ณตํ๋๋ฐ ์ฌ์ฉํฉ๋๋ค.
5. JUnit5 ํ ์คํธ ์ด๋ฆ ํ์ํ๊ธฐ
1. @DisplayNameGeneration
- Method์ Class ๋ ํผ๋ฐ์ค๋ฅผ ์ฌ์ฉํด์ ํ ์คํธ ์ด๋ฆ์ ํ๊ธฐํ๋ ๋ฐฉ๋ฒ์ ์ค์ ํฉ๋๋ค.
- ๊ธฐ๋ณธ ๊ตฌํ์ฒด๋ก ReplaceUnderscores๋ฅผ ์ ๊ณตํฉ๋๋ค.
- ์๋์ ์ฝ๋๋ ์ ๋ ธํ ์ด์ ์ ReplaceUnderScores ์์ฑ์ ์ฃผ์ด ๋ฉ์๋ ๋ค์์ ์ธ๋์ค์ฝ์ด๊ฐ ๊ณต๋ฐฑ์ผ๋ก ๋ฐ๋์ด ์ถ๋ ฅ๋ฉ๋๋ค.
โญ๏ธ Before
public class JUnit5Test {
@Test
void naming_test(){
System.out.println("ํ
์คํธ");
}
}
โญ๏ธAfter
@DisplayNameGeneration(DisplayNameGenerator.ReplaceUnderscores.class)
public class JUnit5Test {
@Test
void naming_test(){
System.out.println("ํ
์คํธ");
}
}
2. @DisplayName
- ์ด๋ค ํ ์คํธ์ธ์ง ํ ์คํธ ์ด๋ฆ์ ๋ณด๋ค ์ฝ๊ฒ ํํํ ์ ์๋ ๋ฐฉ๋ฒ์ ์ ๊ณตํ๋ ์ ๋ ธํ ์ด์ ์ ๋๋ค.
- ๋ฐ๋ผ์ ๋ฉ์๋ ์ด๋ฆ๋ณด๋ค ๋ ์ฝ๊ฒ ์ด๋ค ํ ์คํธ์ธ์ง ํ์ธํ ์ ์์ต๋๋ค.
- @DisplayNameGeneration๋ณด๋ค ์ฐ์ ์์๊ฐ ๋์ต๋๋ค.
โญ๏ธ Before
public class JUnit5Test {
@Test
void naming_test(){
System.out.println("ํ
์คํธ");
}
}
โญ๏ธ After
public class JUnit5Test {
@DisplayName("ํ
์คํธ ์ด๋ฆ ์ง์ ")
@Test
void naming_test(){
System.out.println("ํ
์คํธ");
}
}
6. JUnit5 Assertion
Assertion์ ์ค์ ํ ์คํธ์์ ๊ฒ์ฆํ๊ณ ์ ํ๋ ๋ด์ฉ์ ํ์ธํ๋ ๊ธฐ๋ฅ์ ์ ๊ณตํ๋ ํจํค์ง์ ๋๋ค.
1. assertEquals(expected, actual)
์ค์ ๊ฐ(actual)์ด ๊ธฐ๋ํ ๊ฐ(expected)๊ณผ ๊ฐ์์ง ํ์ธํ๋ ๋ฉ์๋์ ๋๋ค. ํ๋ผ๋ฏธํฐ์ ์์๋ ์๋ฌด๋ ๊ฒ๋ ํด๋ ์๊ด์์ง๋ง ๋ณดํต ์ฒซ ๋ฒ์งธ์ ๊ธฐ๋๊ฐ์ ๋ฃ๊ณ , ๋ ๋ฒ์งธ์ ์ค์ ๋์ค๋ ๊ฐ์ ๋ฃ์ต๋๋ค.
@Test
@DisplayName("์คํฐ๋ ๋ง๋ค๊ธฐ")
void create_new_study() {
Study study = new Study(-10, 25);
assertEquals(StudyStatus.DRAFT, study.getStatus(), "์๋ฌ ๋ฉ์ธ์ง");
assertEquals(StudyStatus.DRAFT, study.getStatus(), () -> "์๋ฌ ๋ฉ์ธ์ง");
assertEquals(StudyStatus.DRAFT, study.getStatus(), String.valueOf(new Supplier<String>() {
@Override
public String get() {
return "์๋ฌ ๋ฉ์ธ์ง";
}
}));
}
assertEquals์์ ์ธ ๋ฒ์งธ ํ๋ผ๋ฏธํฐ์๋ ํด๋น ํ ์คํธ๊ฐ ํต๊ณผํ์ง ๋ชปํ์ ๊ฒฝ์ฐ ๋ณด์ฌ์ฃผ๋ ๋ฉ์ธ์ง๋ฅผ ์ค์ ํ ์ ์์ต๋๋ค. ์ด๋ ์์ ์ธ ๊ฐ์ง ๋ฐฉ๋ฒ์ผ๋ก ์์ฑํ ์ ์๋๋ฐ, ๋๋ค์์ ์จ์ ๋ฉ์ธ์ง๋ฅผ ๊ตฌํํ๋ ๊ฒฝ์ฐ๊ฐ ๊ฐ์ฅ ํจ์จ์ ์ ๋๋ค.
๋๋ค์์ ์จ์ ๋ฉ์ธ์ง๋ฅผ ๊ตฌํํด์ผ ํ๋ ์ด์ .
- ๋ฌธ์์ด ์ฐ์ฐ์ ์คํ์ ํ ์คํธ๊ฐ ์คํจํ์ ๋๋ง ํ๋ค. ๋๋ค์์ด ์๋ ๊ฒฝ์ฐ์๋ ํญ์ ์ฐ์ฐ์ ์ํํ๋ค.
- ๋ฐ๋ผ์ ๋๋ค์์ ์ฌ์ฉํ๋ ๊ฒ์ด ์ฑ๋ฅ ์ ์ฅ์์ ์กฐ๊ธ ์ ๋ฆฌํ ์ ์๋ค.
2. assertNotNull(actual)
๊ฒฐ๊ณผ ๊ฐ(actual)์ด null์ธ์ง ์๋์ง ํ์ธํ๋ ๋ฉ์๋์ ๋๋ค.
@Test
@DisplayName("์คํฐ๋ ๋ง๋ค๊ธฐ")
void create_new_study() {
Study study = new Study(-10, 25);
assertNotNull(study);
}
3. assertTrue(boolean)
๋ค์ ์กฐ๊ฑด์ด ์ฐธ์ธ์ง ํ์ธํ๋ ๋ฉ์๋์ ๋๋ค.
@Test
@DisplayName("๋ฉค๋ฒ ๋ง๋ค๊ธฐ")
void create_new_member() {
Member member = new Member("๊ณ ์์ด");
assertTrue(member.getName().equals("๊ณ ์์ด"), () -> "๋ฉค๋ฒ ์ด๋ฆ์ด ๊ณ ์์ด๊ฐ ์๋๋๋ค.")
}
4. assertAll(executable...)
๋ชจ๋ ํ ์คํธ๋ฅผ ์คํํ๋ ๋ฉ์๋์ ๋๋ค.
๊ธฐ์กด์๋ ์ด์ ์ ํ ์คํธ๊ฐ ์คํจํ๋ฉด ๋ค์ ํ ์คํธ๊ฐ ๋จ์์์์๋ ๋ฐ๋ก ์ข ๋ฃํ์ง๋ง asserAll์ ์ฌ์ฉํ๋ฉด ์ผ๋จ ์ ๋ถ ์ํํฉ๋๋ค.
โญ๏ธ Before
@DisplayName("assertAll")
@Test
void assertAllTest(){
assertTrue(false, ()->"์ฒซ๋ฒ์งธ false์
๋๋ค.");
assertTrue(false, ()->"๋๋ฒ์งธ false์
๋๋ค.");
assertTrue(false, ()->"์ธ๋ฒ์งธ false์
๋๋ค.");
}
โญ๏ธ After
@DisplayName("assertAll")
@Test
void assertAllTest() {
assertAll(
() -> assertTrue(false, () -> "์ฒซ๋ฒ์งธ false์
๋๋ค."),
() -> assertTrue(false, () -> "๋๋ฒ์งธ false์
๋๋ค."),
() -> assertTrue(false, () -> "์ธ๋ฒ์งธ false์
๋๋ค.")
);
}
5. assertThrows(expectedType, executable)
์์ธ๊ฐ ๋ฐ์ํ๋์ง ํ์ธํ๋ ๋ฉ์๋์ ๋๋ค.
@DisplayName("assertThrows")
@Test
void assertThrowsTest() {
Member member = new Member();
member.setName("๊ณ ์์ด");
/*
memberService.join(member)์ ์ํํ์ ๋ IllegalStateException ์๋ฌ๊ฐ ๋ฐ์ํด์ผ ํ
์คํธ๊ฐ ํต๊ณผํ๋ค.
*/
assertThrows(IllegalStateException.class, () -> {
memberService.join(member);
});
}
6. assertTimeout(duration, executable)
ํน์ ์๊ฐ ๋ด์ ํ ์คํธ์ ์คํ์ด ์๋ฃ๋๋์ง ํ์ธํ๋ ๋ฉ์๋์ ๋๋ค.
@Test
@DisplayName("ํน์ ์๊ฐ ์์ ์คํ์ด ์๋ฃ๋๋์ง ํ์ธ")
void timeout_test() {
assertTimeout(Duration.ofSeconds(10), () -> new Study(10, 20));
/*
์๊ฐ์ด 100 millis๊ฐ ์ง๋ฌ๋๋ผ๋ ๋ธ๋ก์์ ๋ชจ๋ ๊ตฌ๋ฌธ์ ์ํํ๊ณ ์ข
๋ฃ๋๋ค.
*/
assertTimeout(Duration.ofMillis(100), () -> {
new Study(10, 20);
Thread.sleep(300);
System.out.println("here~");
});
/*
์๊ฐ์ด ์ค๋ฒ๋๋ฉด ๋ธ๋ก์์ ๊ตฌ๋ฌธ์ ๋ ์ด์ ์ํํ์ง ์๊ณ ๋ฐ๋ก ํ
์คํธ๋ฅผ ์ข
๋ฃ์ํจ๋ค.
ThreadLocal ์ ์ฌ์ฉ ํ ๊ฒฝ์ฐ ์์์น ๋ชปํ ๊ฒฝ์ฐ๊ฐ ๋ฐ์ํ ๊ฐ๋ฅ์ฑ์ด ์๋ค.
*/
assertTimeoutPreemptively(Duration.ofMillis(100), () -> {
new Study(10, 20);
Thread.sleep(300);
System.out.println("not here~");
});
}
Assertion์ ๊ฐ๋ ์ฑ์ด ์ข์ง ์์ AssertThat์ผ๋ก ์์ํ๋ AssertJ๋ฅผ ์์ฆ์ ๋ง์ด ์ฌ์ฉํ๋ค๊ณ ํฉ๋๋ค.
AssertJ๋ AssertThat("actual").isEqualTo("actual)์ ๊ฐ์ด ๋ฉ์๋ ์ฒด์ด๋ ๋ฐฉ์์ ์ฌ์ฉํฉ๋๋ค.
AssertJ ๊ฐ์ ๊ฒฝ์ฐ ์ด์ ์ ์ ๋ฆฌํ ์ ์ด ์์ผ๋ฉฐ, ์๋์ ๊ฒ์๊ธ์์ ํ์ธ์ด ๊ฐ๋ฅํฉ๋๋ค.
7. ์กฐ๊ฑด์ ๋ฐ๋ผ ํ ์คํธ ์คํํ๊ธฐ
JUnit์์๋ ํน์ ํ ์กฐ๊ฑด์ ๋ง์กฑํ๋ ๊ฒฝ์ฐ์ ํ ์คํธ๋ฅผ ์คํํ ์ ์๋ ๋ฐฉ๋ฒ์ ์ ๊ณตํ๊ณ ์์ต๋๋ค.
ex) ํน์ ํ OS, ํ๊ฒฝ๋ณ์, ์์คํ ๋ณ์์ ๋ฐ๋ผ ํ ์คํธ๋ฅผ ์คํํด์ผ ํ ์ง ๋ง์ง๋ฅผ ๊ฒฐ์ ํด์ผ ํ๋ ๊ฒฝ์ฐ
org.junit.jupiter.api.Assumptions.*
- assumeTrue(์กฐ๊ฑด) : ํด๋น ์กฐ๊ฑด์ด ํต๊ณผํด์ผ ์๋ ๋ก์ง๋ค์ด ์ํ๋๋ค.
- assumingThat(์กฐ๊ฑด, ํ ์คํธ): ์กฐ๊ฑด์ด ํต๊ณผ๋ฅผ ํด์ผ ๋ ๋ฒ์งธ ํ๋ผ๋ฏธํฐ๋ก ์ ๋ฌํ ํ ์คํธ(๋ก์ง)๊ฐ ์ํ๋๋ค.
@Test
@DisplayName("์กฐ๊ฑด์ ๋ฐ๋ผ ํ
์คํธ ์คํํ๊ธฐ")
void condition_test() {
String test_env = System.getenv("TEST_ENV");
System.out.println(test_env);
/*
์กฐ๊ฑด์ ๋ง์กฑํ ๊ฒฝ์ฐ์๋ง ๋ค์ ํ
์คํธ๋ก ๋์ด๊ฐ๋ผ
*/
assumeFalse("LOCAL".equalsIgnoreCase(test_env));
System.out.println("์ถ๋ ฅ๋์ง ์์.");
/*
์กฐ๊ฑด์ ๋ถํฉํ ๊ฒฝ์ฐ์๋ง ๋ค์์ ํ
์คํธ๋ฅผ ์ํํ๊ณ , ์๋๋ผ๋ฉด ๋์ด๊ฐ๋ผ.
*/
assumingThat("LOCAL".equalsIgnoreCase(test_env), () -> {
System.out.println("์ถ๋ ฅ ๋จ");
});
}
์ ๋ ธํ ์ด์ ์ผ๋ก ๋ค์๊ณผ ๊ฐ์ด ์กฐ๊ฑด์ ์ค์ ํ ์๋ ์์ต๋๋ค.
- @EnabledOnOs: ํน์ OS์ผ๋๋ง ํ ์คํธ๊ฐ ๋์ํ๋๋ก ํฉ๋๋ค.
- @EnableOnJre: ํน์ JRE ๋ฒ์ ์ผ๋๋ง ํ ์คํธ๊ฐ ๋์ํ๋๋ก ํฉ๋๋ค.
@Test
@DisplayName("์ด์์ฒด์ ๊ฐ mac์ธ ๊ฒฝ์ฐ")
@EnabledOnOs(OS.MAC)
void macOS_test() {
System.out.println("macOS์
๋๋ค.");
}
@Test
@DisplayName("์ด์์ฒด์ ๊ฐ window์ธ ๊ฒฝ์ฐ")
@EnabledOnOs(OS.WINDOWS)
void windowOS_test() {
System.out.println("windowOS์
๋๋ค.");
}
@Test
@DisplayName("์ด์์ฒด์ ๊ฐ window ํน์ mac์ธ ๊ฒฝ์ฐ")
@EnabledOnOs({OS.WINDOWS, OS.MAC})
void windowOS_macOS_test() {
System.out.println("windowOS ํน์ macOS์
๋๋ค.");
}
@Test
@DisplayName("ํน์ ์๋ฐ ๋ฒ์ ๋ง ์คํํด๋ผ")
@EnabledOnJre(JRE.JAVA_11)
void Jre_test() {
System.out.println("JAVA_11์
๋๋ค.");
}
8. ํ๊น ๊ณผ ํํฐ๋ง
JUnit5์์๋ ํ ์คํธ ๊ทธ๋ฃน์ ๋ง๋ค๊ณ ์ํ๋ ํ ์คํธ ๊ทธ๋ฃน๋ง ํ ์คํธ๋ฅผ ์คํํ ์ ์๋ ๊ธฐ๋ฅ์ ์ ๊ณตํฉ๋๋ค.
@Tag: ํ์คํธ ๋ฉ์๋์ ์ถ๊ฐํ ์ ์๋ ํ๊ทธ ์ ๋ ธํ ์ด์ ์ผ๋ก ํ๋์ ํ ์คํธ ๋ฉ์๋์ ์ฌ๋ฌ ํ๊ทธ๋ฅผ ์ฌ์ฉํ ์๋ ์์ต๋๋ค.
/*
fast ํ๊ทธ๋ ๋ก์ปฌ์์ ์ํํ๋ค๊ณ ๊ฐ์ .
*/
@Test
@DisplayName("Tag ํ
์คํธ")
@Tag("fast")
void tag1_test() {
Study actual = new Study(20, 20);
assertNotNull(actual);
}
/*
slow ํ๊ทธ๋ CI ํ๊ฒฝ์์ ์ํ ํ๋ค๊ณ ๊ฐ์ .
*/
@Test
@DisplayName("Tag ํ
์คํธ")
@Tag("slow")
void tag2_test() {
Study actual = new Study(20, 20);
assertNotNull(actual);
}
์์ฒ๋ผ fast์ slowํ ์คํธ๋ฅผ ๋ง๋ค๊ณ , fast๋ ๋ก์ปฌ์์, ์ค๋ ์๊ฐ์ด ์์๋๋ slow๋ CI์์ ์ํํ๋ค๊ณ ๊ฐ์ ํ ์ ์์ต๋๋ค. ํ๊ทธ ์ง์ ํ ์ํ๋ ํ๊ทธ๋ง ์คํ๋ ์ ์๋๋ก ์๋์ ๊ฐ์ด ํํฐ๋ง ์์ ์ด ํ์ํฉ๋๋ค.
ํํฐ๋ง ๋ฐฉ๋ฒ(MAC ๊ธฐ์ค)
InteliJ -> Run -> Edit Configurations... -> ์ข์ธก์ + ๋ฒํผ -> JUnit ์ ํ -> ์ํ๋ ํ๊ทธ ์ธํ
Maven์ ์ฌ์ฉํ๋ค๋ฉด ์๋์ ๊ฐ์ด Maven - pom.xml ์์ฑ์ ํตํด ํํฐ๋ง ์ค์ ์ด ๊ฐ๋ฅํฉ๋๋ค. (| ์ฐ์ฐ์๋ฅผ ์ด์ฉํด ๋ค์์ ํ๊ทธ๋ ์ง์ ๊ฐ๋ฅํฉ๋๋ค.)
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<groups>fast | slow</groups>
</configuration>
</plugin>
9. ํ ์คํธ ๋ฐ๋ณตํ๊ธฐ
์ธ์๊ฐ ๋๋ค๊ฐ์ด๊ฑฐ๋, ํ ์คํธ ๋ฐ์ ์์ ์ ๋ฐ๋ผ ๋ฌ๋ผ์ง๋ ๊ฐ ๋๋ฌธ์, ํ ์คํธ ๋ด์ฉ์ด ๋ฐ๋ณต๋์ผํ๋ ๊ฒฝ์ฐ์๋ ์ด๋ป๊ฒ ํด์ผ ํ ๊น์? JUnit์์๋ ์ด๋ฌํ ํ ์คํธ ๋ฐ๋ณต์ ์ํ ์ ๋ ธํ ์ด์ ์ ์ ๊ณตํฉ๋๋ค.
1. @RepeatedTest
๋ฐ๋ณต ํ์์ ๋ฐ๋ณต ํ ์คํธ ์ด๋ฆ์ ์ค์ ํ๋ ์ ๋ ธํ ์ด์ ์ ๋๋ค.
- {displayName}: @DisplayName์ผ๋ก ์ค์ ํ ํ ์คํธ์ ์ด๋ฆ์ ๊ฐ์ ธ์ต๋๋ค.
- {currentRepetition}: ํ์ฌ ํ ์คํธ๊ฐ ๋ช ๋ฒ ๋ฐ๋ณต๋์๋์ง ๊ฐ์ ๊ฐ์ ธ์ต๋๋ค.
- {totalRepetition}: ์ ์ฒด ํ ์คํธ๊ฐ ๋ช๋ฒ ๋ฐ๋ณต๋๋์ง ๊ฐ์ ๊ฐ์ ธ์ต๋๋ค.
@DisplayName("ํ
์คํธ ๋ฐ๋ณตํ๊ธฐ")
@RepeatedTest(3)
void repeat_test_v1() {
System.out.println("๋ฐ๋ณต");
}
@DisplayName("ํ
์คํธ ํ์ฌ ํ์์ ๋จ์ ํ์ ์ถ๋ ฅํ๊ธฐ")
@RepeatedTest(3)
void repeat_test_v2(RepetitionInfo repeatInfo) {
System.out.println("๋ฐ๋ณต " + repeatInfo.getCurrentRepetition() + "/" + repeatInfo.getTotalRepetitions());
}
@DisplayName("ํ
์คํธ ์ด๋ฆ ๋ช
์ํ๊ธฐ")
@RepeatedTest(value = 3, name = "{currentRepetition}/{totalRepetitions}")
void repeat_test_v3(RepetitionInfo repeatInfo) {
System.out.println("๋ฐ๋ณต " + repeatInfo.getCurrentRepetition() + "/" + repeatInfo.getTotalRepetitions());
}
2. @ParameterizedTest
ํ ์คํธ์ ์ฌ๋ฌ ๋ค๋ฅธ ๋งค๊ฐ๋ณ์๋ฅผ ๋์ ํด๊ฐ๋ฉฐ ๋ฐ๋ณต ์คํํ๋ ์ ๋ ธํ ์ด์ ์ ๋๋ค.
- @ValueSource: ์์ฑ์ ์ ์ธํด ์ค ํ๋ผ๋ฏธํฐ๋ฅผ ์ธ์ ๊ฐ์ผ๋ก ์ ๋ฌํ๋๋ฐ, Stringํ์ ๋ฟ ๋ง ์๋๋ผ ๋ชจ๋ ์์ ํ์ ์ ์ง์ํฉ๋๋ค.
- {displayName}: @DisplayName ์ ๋ ธํ ์ด์ ์ผ๋ก ์ค์ ํ ํ ์คํธ์ ์ด๋ฆ
- {index}: ํ์ฌ ๋ฐ๋ณต๋ ํ ์คํธ์ ์ธ๋ฑ์ค
- {arguments}: ์ ๋ฌ๋๋ ์ธ๋ฑ์ค ์ ์ฒด
- {0}, {1} ...: ํ๋ผ๋ฏธํฐ๋ฅผ ์ธ๋ฑ์ค๋ก ์กฐํ
/*
๋ฐ๋ณต์ ์ธ ํ
์คํธ๋ฅผ ํ ๋ ๋ง๋ค ๋ค๋ฅธ ๊ฐ์ ๊ฐ์ง๊ณ ํ
์คํธ๋ฅผ ํ๊ณ ์ถ๋ค.
*/
@DisplayName("๋ฐ๋ณต์ ์ธ ํ
์คํธ ๋ง๋ค ๋ค๋ฅธ ๊ฐ์ ๊ฐ์ง๊ณ ํ
์คํธํ๊ธฐ")
@ParameterizedTest(name = "{index} {displayName} message={0}")
@ValueSource(strings = {"๋ ์จ๊ฐ", "๋ง์ด", "์ถ์์ง๊ณ ", "์๋ค์"})
void parameterizedTest(String message) {
System.out.println(message);
}
@DisplayName("๋ฐ๋ณต์ ์ธ ํ
์คํธ ๋ง๋ค ๋ค๋ฅธ ๊ฐ์ ๊ฐ์ง๊ณ ํ
์คํธํ๊ธฐ")
@ParameterizedTest(name = "{index} {displayName} message={0}")
@ValueSource(ints = {10, 20, 40})
void parameterizedTest(Integer message) {
System.out.println(message);
}
3. ์ธ์ ๊ฐ๋ค์ ์์ค
์ธ์ ๊ฐ๋ค์ ์ ๊ณตํด์ฃผ๋ ์ ๋ ธํ ์ด์ ์ ๋ ๋ค์ํ๊ฒ ์กด์ฌํฉ๋๋ค.
- @ValueSource: ๋ค์ํ ๊ธฐ๋ณธ ํ์ ์ ์ธ์ ๊ฐ์ ์ ๋ฌํ ์ ์์ต๋๋ค.
- @NullSource, @EmptySource, @NullAndEmptySource: Null๊ณผ ๊ณต๋ฐฑ ๋ฌธ์๋ฅผ ๊ฐ๊ฐ ์ ๊ณตํด์ฃผ๊ฑฐ๋ ํ ๋ฒ์ ์ ๊ณตํด ์ค ์ ์์ต๋๋ค.
- @EnumSource: Enum์ ๊ฐ์ ์ ๊ณตํ ์ ์์ต๋๋ค.
/*
EmptySource๋ฅผ ์ฌ์ฉํ๋ฉด ๋น์ด์๋ ๋ฌธ์์ด์ ํ๋ ์ถ๊ฐํด ์ค๋ค.
*/
@DisplayName("๋ฐ๋ณต์ ์ธ ํ
์คํธ ๋ง๋ค ๋ค๋ฅธ ๊ฐ์ ๊ฐ์ง๊ณ ํ
์คํธํ๊ธฐ")
@ParameterizedTest(name = "{index} {displayName} message={0}")
@ValueSource(strings = {"๋ ์จ๊ฐ", "๋ง์ด", "์ถ์์ง๊ณ ", "์๋ค์"})
@EmptySource
void parameterizedWithEmptySourceTest(String message) {
System.out.println(message);
}
/*
NullSource๋ฅผ ์ฌ์ฉํ๋ฉด Null์ ํ๋ ์ถ๊ฐํด ์ค๋ค.
*/
@DisplayName("๋ฐ๋ณต์ ์ธ ํ
์คํธ ๋ง๋ค ๋ค๋ฅธ ๊ฐ์ ๊ฐ์ง๊ณ ํ
์คํธํ๊ธฐ")
@ParameterizedTest(name = "{index} {displayName} message={0}")
@ValueSource(strings = {"๋ ์จ๊ฐ", "๋ง์ด", "์ถ์์ง๊ณ ", "์๋ค์"})
@NullSource
void parameterizedWithNullSourceTest(String message) {
System.out.println(message);
}
/*
NullAndEmptySource๋ฅผ ์ฌ์ฉํ๋ฉด Null๊ณผ ๋น ๋ฌธ์์ด์ ํ๋ ์ถ๊ฐํด ์ค๋ค.
*/
@DisplayName("๋ฐ๋ณต์ ์ธ ํ
์คํธ ๋ง๋ค ๋ค๋ฅธ ๊ฐ์ ๊ฐ์ง๊ณ ํ
์คํธํ๊ธฐ")
@ParameterizedTest(name = "{index} {displayName} message={0}")
@ValueSource(strings = {"๋ ์จ๊ฐ", "๋ง์ด", "์ถ์์ง๊ณ ", "์๋ค์"})
@NullAndEmptySource
void parameterizedWithNullAndEmptySourceTest(String message) {
System.out.println(message);
}
10. ํ ์คํธ ์ธ์คํด์ค
JUnit์ ๊ธฐ๋ณธ์ ์ผ๋ก ํ ์คํธ ๋ฉ์๋๋ง๋ค ํ ์คํธ ์ธ์คํด์ค๋ฅผ ์๋ก ๋ง๋ญ๋๋ค.
์ด๊ฒ์ด ๊ธฐ๋ณธ ์ ๋ต์ด๋ฉฐ, ํ ์คํธ ๋ฉ์๋๋ฅผ ๋ ๋ฆฝ์ ์ผ๋ก ์คํํ์ฌ ์์์น ๋ชปํ ๋ค๋ฅธ ํ ์คํธ๋ก๋ถํฐ์ ๋ถ์์ฉ์ ๋ฐฉ์งํ๊ธฐ ์ํจ์ ๋๋ค. ํ์ง๋ง JUnit5๋ถํฐ๋ ์ํฉ์ ๋ฐ๋ผ ์ด๋ฌํ ์ ๋ต์ ๋ณ๊ฒฝํ ์ ์์ต๋๋ค.
@TestInstance(Lifecycle.PER_CLASS)
- ํ ์คํธ ํด๋์ค๋น ์ธ์คํด์ค๋ฅผ ํ๋๋ง ๋ง๋ค์ด ์ฌ์ฉํฉ๋๋ค.
- ๊ฒฝ์ฐ์ ๋ฐ๋ผ ํ ์คํธ ๊ฐ์ ๊ณต์ ํ๋ ๋ชจ๋ ์ํ๋ฅผ @BeforeEach ๋๋ @AfterEach์์ ์ด๊ธฐํํ ํ์๊ฐ ์์ต๋๋ค.
- @BeforeAll๊ณผ @AfterAll์ ์ธ์คํด์ค ๋ฉ์๋ ๋๋ ์ธํฐํ์ด์ค์ ์ ์ํ default ๋ฉ์๋๋ก ์ ์ํ ์๋ ์์ต๋๋ค.
โญ๏ธ Before
public class InstanceTest {
int _instance = 1;
@AfterEach
void plus() {
_instance++;
}
@RepeatedTest(10)
void test() {
System.out.println(_instance);
}
}
@TestInstance(Lifecycle.PER_CLASS) ์ ์ฉ ์ ์ ๋ชจ์ต์ ๋๋ค. ๋ถ๋ช @AfterEach๋ฅผ ํตํด์ ๋งค๋ฒ ํ ์คํธ๊ฐ ๋๋ ๋๋ง๋ค _instance ๊ฐ์ +1 ํ๋๋ก ์ค์ ํ์ง๋ง ๋งค ํ ์คํธ๋ 1์ด ์ถ๋ ฅ๋๋ ๋ชจ์ต์ ํ์ธํ ์ ์์ต๋๋ค.
โญ๏ธ After
@TestInstance(Lifecycle.PER_CLASS)
public class InstanceTest {
int _instance = 1;
@AfterEach
void plus() {
_instance++;
}
@RepeatedTest(10)
void test() {
System.out.println(_instance);
}
}
@TestInstance(Lifecycle.PER_CLASS) ์ ์ฉ ํ์ ๋ชจ์ต์ ๋๋ค. ํ ์คํธ ํด๋์ค์ ์ธ์คํด์ค๋ฅผ ๋ชจ๋ ํ ์คํธ๊ฐ ๊ณต์ ํด์ ์ฌ์ฉํฉ๋๋ค. ์ํ๋ ๋๋ก _instance๊ฐ์ด ์ฆ๊ฐํด์ ์ถ๋ ฅ๋๋ ๊ฒ์ ํ์ธํ ์ ์์ต๋๋ค.
11. ํ ์คํธ ์์
ํ ์คํธ ๋ฉ์๋๋ ์ ์ ํ ์์๋๋ก ์ฐจ๋ก๋๋ก ์คํ๋์ง ์์ต๋๋ค. ์๋ํ๋ฉด ํ๋์ ๋จ์(ํ ์คํธ)๋ ๋ ๋ฆฝ์ ์ผ๋ก ์คํ๋๋ฉฐ ๋ค๋ฅธ ๋ฉ์๋์ ์ํฅ์ ์ฃผ๋ฉด ์ ๋๊ธฐ ๋๋ฌธ์ ๋๋ค.(ํ ์คํธ ์ธ์คํด์ค๋ฅผ ํ ์คํธ๋ง๋ค ์๋ก ๋ง๋๋ ๊ฒ๊ณผ ๊ฐ์ ์ด์ )
ํ์ง๋ง ํน์ ์์๋๋ก ํ ์คํธ๋ฅผ ์คํํด์ผ ํ๋ ๊ฒฝ์ฐ๊ฐ ์๋ค๋ฉด ์ ๋ ธํ ์ด์ ์ ํตํด ์ด ํ ์คํธ ๋ฉ์๋์ ์คํ ์์๋ฅผ ์ปจํธ๋กค ํ ์ ์์ต๋๋ค.
@TestMethodOrder(MethodOrderer.OrderAnnotation.class) // ํ
์คํธ์ ์คํ ์์๋ฅผ ์ง์ ํด ์ค ์ ์๋ค. ๊ธฐ๋ณธ์ ์ผ๋ก๋ ์คํ์์๋ฅผ ๋ณด์ฅํ์ง ์๊ธฐ ๋๋ฌธ์ด๋ค.
public class OrderTest {
@DisplayName("์ด ํ
์คํธ๊ฐ ๋๋ฒ์งธ ์์๋ก ์คํ๋์ด์ผ ํ๋ค.")
@Test
@Order(2)
void secondTest() {
System.out.println("๋ ๋ฒ์งธ๋ก ์คํ๋์ด์ผ๋ง ํ๋ ํ
์คํธ์
๋๋ค.");
}
@DisplayName("์ด ํ
์คํธ๊ฐ ์ธ๋ฒ์งธ ์์๋ก ์คํ๋์ด์ผ ํ๋ค.")
@Test
@Order(3)
void thirdTest() {
System.out.println("์ธ ๋ฒ์งธ๋ก ์คํ๋์ด์ผ๋ง ํ๋ ํ
์คํธ์
๋๋ค.");
}
@DisplayName("์ด ํ
์คํธ๊ฐ ์ฒซ๋ฒ์งธ ์์๋ก ์คํ๋์ด์ผ ํ๋ค.")
@Test
@Order(1)
void firstTest() {
System.out.println("์ฒซ ๋ฒ์งธ๋ก ์คํ๋์ด์ผ๋ง ํ๋ ํ
์คํธ์
๋๋ค.");
}
ํ ์คํธ ๊ด๋ จ ๊ฐ์ด ๋ณด๋ฉด ์ข์ ๊ธ
'BackEnd๐ฑ > Spring' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
Spring JDBC๋ฅผ ์ฌ์ฉํ์ฌ Batch Insert ์ํํ๊ธฐ (2) | 2023.01.09 |
---|---|
Actuator Refresh ๋ฐ์ ์๋๋ ํ์ ํด๊ฒฐ (2) | 2022.11.12 |
Actuator dependency and Swagger Stater 3.0.0 ์ถฉ๋ ์๋ฌ (0) | 2022.11.11 |
[Spring] StringUtils ์ ์ฉํ ๋ฉ์๋ ์ ๋ฆฌ (0) | 2022.08.31 |
AssertJ ํต์ฌ ๊ธฐ๋ฅ ์์๋ณด๊ธฐ (1) | 2022.08.08 |
[Querydsl] unable to load class com.mysema.codegen.model.type'. error (1) | 2022.07.31 |
๋๊ธ