JUnit5 사용하기
- pom.xml 파일에 의존성을 추가한다.
- https://mvnrepository.com/artifact/org.junit.jupiter/junit-jupiter-api
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<version>5.7.0</version>
<scope>test</scope>
</dependency>
2.2버전 이상의 스프링 부트 프로젝트를 생성하면 따로 추가하지않아도 기본으로 의존성이 추가된다.
기본 어노테이션
- @Test : 해당 메서드가 테스트 메서드임을 선언한다.
- @BeforeAll / @AfterAll : 테스트 클래스에 있는 모든테스트를 실행하기 전, 후에 딱 한번만 실행되며 static 메서드여야함.
- @BeforeEach / @AfterEach : 각각의 테스트 메서드를 실행하기 전, 후에 호출된다.
- @Disabled : 테스트 메서드에 사용하여 해당 테스트 메서드를 실행하지 않도록 한다.
import org.junit.jupiter.api.*;
class TestSampleTest {
@Test
void testMethod1() {
System.out.println("test method1");
}
@Test
void testMethod2() {
System.out.println("test method2");
}
@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
@Disabled
void testMethod3() {
System.out.println("test mehthod3");
}
}
테스트 실행 결과 볼 수 있듯이 BeforeAll은 최초 테스트 시작시에 1번 실행, AfterAll은 모든 테스트를 수행 한뒤 마지막에 1번 실행되었다.
BeforeEach, AfterEach는 각각의 테스트 메서드가 실행 되기 전 후에 실행되었다.
@Disabled 어노테이션을 적용한 testMethod3()는 결과창에서 볼 수 있듯이 실행되지 않았다.
특정 메서드에 커서를 두고 테스트를 실행하면 해당 메서드만 테스트를 실행한다.
테스트에 이름 추가하기
@Display 어노테이션을 사용하여 테스트 클래스 또는 테스트 메서드에 이름을 추가할 수 있으며 심지어 이모지도 테스트 이름으로 사용할 수 있다.
import org.junit.jupiter.api.*;
@DisplayName("테스트 클래스")
class TestSampleTest {
@DisplayName("테스트 메서드1")
@Test
void testMethod1() {
System.out.println("test method1");
}
@DisplayName("👏")
@Test
void testMethod2() {
System.out.println("test method2");
}
}
Assertion 메서드로 테스트하기
- assertEqualse(expected, actual[, message]) : 기대하는 값과 실제 값이 일치하는지 테스트한다.
- assertNotNull(actual) : 파라미터로 전달된 값이 null인지 아닌지 테스트한다.
- assertTrue(condition) : 파리미터로 전달된 조건이 true인지 테스트한다.
- assertThrows(expectedType, executable) : 특정 예외가 발생하는지 테스트한다.
@Test
void personTest() {
Person p = new Person("steve", 26);
assertTrue(p.getAge() > 19, "나이는 19세 이상이어야 합니다.");
// 람다식으로 메시지 전달
assertEquals(26, p.getAge(), () -> "나이는 " + p.getAge() + "세 이여야합니다.");
assertNotNull(p);
Exception exception = assertThrows(SampleException.class, () -> p.throwSampleException());
assertEquals("exception sample", exception.getMessage());
}
파라미터로 문자열을 전달하여 테스트에 실패시 특정 메시지를 출력할 수 도있다.
메시지 문자열의 연산이 필요할 때 일반적인 문자열로 전달 시 테스트 실패 여부와 상관없이 문자열 연산을 무조건 수행한다.
위 코드의 assertEquals() 메서드에처서첨 람다식으로 문자열을 전달시 테스트에 실패했을 때만 문자열 연산을 수행하기 때문에 연산이 많이 수행되는 문자열의 경우에는 람다식을 이용하여 메시지를 전달하는 것이 좋다.
assertThrows() 메서드의 경우 변수로 할당하여 예외 메시지를 비교해 볼 수도 있다.
- assertAll(exetables)
- 여러개의 assert 메서드를 람다식으로 묶어서 사용.
- 이 메서드를 사용하면 중간에 테스트가 실패해도 나머지 테스트를 계속해서 수행할 수 있다
@Test
void assertAllTest() {
Person p = new Person("steve", 26);
assertAll(
() -> assertTrue(p.getAge() > 30, "나이는 30세 이상이어야 합니다."),
() -> assertEquals(27, p.getAge(), () -> "나이 " + p.getAge() + "세 입니다."),
() -> assertNotNull(p)
);
}
테스트 실행 결과 assertTrue()에서 실패했지만 나머지 테스트도 정상적으로 수행된 것을 알 수 있습니다.
- assertTimeout(time, executable) : 특정 시간 안에 실행이 완료되는지 테스트한다.
- Duration.of- 메서드를 이용하여 시간 단위를 설정할 수 있다.
```
@Test
void timeoutTest() {
assertTimeout(Duration.ofMillis(1000), () -> {
// .. test code
Thread.sleep(2000);
}, "시간이 초과되었습니다.");
}
```
위 코드에서는 테스트 시간을 1초로 설정하였지만 sleep() 메서드를 사용하여 의도적으로 2초를 지연하였기 때문에 테스트에 실패한 모습을 불 수 있다.
조건에 따라 테스트하기
assumeTrue(조건) 메서드를 사용하여 특정 조건을 만족하는 경우에만 남은 테스트 코드를 실행하게 할 수 있다.
int n = 10;
@Test
void assumeTrueTest() {
assumeTrue(n > 0);
//n이 0보다 크다면 남은 코드 실행
}
assumingThat(조건, 테스트 코드) 메서드를 사용하여 특정 조건을 만족하는 경우에 특정 테스트 코드를 실행하게 할 수 있다.
int n = 10;
@Test
void assumingThatTest() {
assumingThat(n > 10, () -> {
//n이 10보다 크다면 실행
});
}
이 밖에 @EnabledXX, @DisabledXX 어노테이션을 사용하여 경우에 따라 테스트를 실행하거나 실행하지 않을 수 도 있다.
몇가지 예를 들어보면 다음과 같다.
//MacOS를 사용중이라면 테스트를 실행한다.
@EnabledOnOs(OS.MAC)
//WINDWS 또는 LINUX 운영체제를 사용한다면 테스트를 실행하지 않는다.
@DisabledOnOs({OS.WINDOWS, OS.LINUX})
//JRE 버전이 11이면 테스트 실행한다.
@EnabledOnJre(JRE.JAVA_11)
//JRE 버전이 8 또는 9라면 테스트를 실행하지 않는다.
@DisabledOnJre({JRE.JAVA_8, JRE.JAVA_9})
테스트 전략 변경
JUnit은 기본적으로 테스트 메서드당 하나의 인스턴스를 생성하는 전략을 사용한다.
JUnit5에서는 이 전략을 테스트 클래스 당 하나의 인스턴스만 생성해서 공유할 수 있도록하는 방법이 추가되었다.
테스트 클래스에 @TestInstance 어노테이션을 사용하여 매개변수로 TestInstance.Lifecycle.PER_CLASS 를 전달하여 전략을 변경할 수 있다.
또한 인스턴스를 하나 밖에 생성하지 않기 때문에 @BeforeAll, @AfterAll 테스트 메서드를 static 으로 선언하지 않아도 된다.
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
class SampleTest {
int num = 0;
@Test
void testMethod1() {
System.out.println(num++);
System.out.println(this);
}
@Test
void testMethod2() {
System.out.println(num++);
System.out.println(this);
}
@AfterAll
void afterAll() {
System.out.println("after all");
}
@BeforeAll
void beforeAll() {
System.out.println("before all");
}
}
위 코드를 실행하면 다음과 같은 결과가 나오며 num 값이 1로 증가한 것과 인스턴스의 주소를 출력했을 때 같은 주소가 나오는 것을 볼 수 있다.
테스트 순서 변경하기
테스트는 JUnit 내부적으로 정해진 로직에 따라 순서가 정해져 실행되게 된다.
JUnit5부터는 기본적으로 테스트 클래스에 선언된 메서드 순서대로 테스트가 수행되긴하지만 이 순서가 무조건 유지된다고 생각하면 안된다.
필요에 따라 특정 순서대로 테스트를 실행하고 싶다면 클래스에는 @TestMehodOrder 애노테이션을, 메서드에는 @Order 어노테이션을 사용하여 순서를 지정해주면 된다.
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
class SampleTest {
@Test
@Order(2)
void testMethod1() {
System.out.println("test1");
}
@Test
@Order(3)
void testMethod2() {
System.out.println("test2");
}
@Test
@Order(1)
void testMethod3() {
System.out.println("test3");
}
}
테스트 결과에서 볼 수 있듯이 Order로 전달된 숫자가 낮을수록 우선순위가 높다.
JUnit5 확장 모델
JUnit4의 확장 모델은 @RunWith(Runner), TestRule, MethodRule.
JUnit5의 확장 모델은 Extension 하나로 구성되어있다.
확장 클래스 작성
org.junit.api.extension 패키지의 아래에 있는 다음 인터페이스들은 테스트 실행 생명주기의 다양한 지점에서 테스트를 확장하기 위한 API를 제공한다.
- BeforeAllCallback : 모든 테스트가 실행되기전 딱 한번 추가 동작을 제공하는 Extension API
- BeforeEachCallback : 각각의 테스트가 실행되기 전 테스트에 추가 동작을 제공하는 Extension API.
- BeforeTestExecutionCallback : 각각의 테스트가 실행되기 전에 추가 동작을 제공하지만, 테스트 메서드가 실행된 후에 테스트에 추가 동작을 제공하는 Extensino API.
- AfterTestExecutionCallback : 각각의 테스트가 실행된 직후 @AfterEach와 같은 메서드가 실행되기 전에 테스트에 추가 동작을 제공하는 Extension API.
- AfterEachCallBack : 각각의 테스트의 @AfterEach와 같은 메서드가 실행 된후 테스트에 추가 동작을 제공하는 Extension API.
- BeforeEachCallback : 각각의 테스트가 실행되기 전 테스트에 추가 동작을 제공하는 Extension API.
- AfterAllCallBack : 모든 테스트가 실행된 후 딱 한번 테스트에 추가 동작을 제공하는 Extension API.
등록 방법
- @ExtendWith : 선언적인 등록
- @RegisterExtension : 프로그래밍적 등록
- 자동 등록 자바 ServiceLoader 이용 : 원하지 않는 Extension을 사용하게 되는 경우도 발생할 수 있어 명시적으로 선언해주는 것이 좋다.
참고
'자바 > 스터디' 카테고리의 다른 글
[자바 스터디] 6주차 과제 - 상속 (0) | 2020.12.25 |
---|---|
[자바 스터디] 5주차 과제 - 클래스 (0) | 2020.12.17 |
[자바 스터디] 4주차 과제 : 제어문 (2) | 2020.12.11 |
[자바 스터디] 3주차 과제 : 연산자 (0) | 2020.12.01 |
[자바 스터디] 2주차 과제 : 자바 데이터 타입, 변수 그리고 배열 (0) | 2020.11.21 |
댓글