테스트 코드를 작성하다 보면 각각 중복되는 작업이 많이 생깁니다. 예를 들면 각 테스트 전에 테스트 수행에 필요한 객체를 만들거나 테스트 데이터를 초기화하는 작업 등이 있습니다.
JUnit은 이러한 중복 작업에 대해 편리하게 작업이 가능하도록 라이프 사이클 메서드 어노테이션을 제공합니다.
@BeforeEach
테스트 메서드 전에 실행됩니다.
테스트 전에 필요한 객체를 생성하거나 테스트 데이터 설정에 자주 사용합니다.
@AfterEach
테스트 메서드 후에 실행됩니다.
테스트 후에 테스트 데이터를 다시 초기화 하는 작업에 많이 사용됩니다.
실행 순서 다이어그램을 먼저 보여드리고 코드로 어노테이션 예시를 보여드리겠습니다.
@BeforeEach를 어떤 상황에 적용 가능한지 코드를 통해 보여드리면
// @BeforeEach 적용 전
class DemoUtilsTest {
@Test
void testEqualsAndNotEquals() {
DemoUtils demoUtils = new DemoUtils(); // 중복
assertEquals(6, demoUtils.add(2, 4), "2 + 4 must be 6");
assertNotEquals(6, demoUtils.add(1, 9), "1 + 9 must not be 6");
}
@Test
void testNullAndNotNull() {
DemoUtils demoUtils = new DemoUtils(); // 중복
assertNull(demoUtils.checkNull(null), "Object should be null");
assertNotNull(demoUtils.checkNull("dami"), "Object should not be null");
}
}
코드를 보면 각 테스트 마다 DemoUtils demoUtils = new DemoUtils(); 객체를 생성해서 객체의 메서드를 통해 테스트를 수행하는 것을 볼 수 있습니다.
아래와 같이 테스트 실행 전 필요한 객체생성의 중복 코드를 없앨때 활용됩니다.
// @BeforeEach 적용 후
class DemoUtilsTest {
private DemoUtils demoUtils;
@BeforeEach
void setupBeforeEach(){
demoUtils = new DemoUtils();
System.out.println("call @BeforeEach");
}
@Test
void testEqualsAndNotEquals() {
assertEquals(6, demoUtils.add(2, 4), "2 + 4 must be 6");
assertNotEquals(6, demoUtils.add(1, 9), "1 + 9 must not be 6");
}
@Test
void testNullAndNotNull() {
assertNull(demoUtils.checkNull(null), "Object should be null");
assertNotNull(demoUtils.checkNull("dami"), "Object should not be null");
}
}
이어서 @AfterEach의 사용 예시를 보여드리겠습니다.
@AfterEach는 각 테스트 수행 후 데이터를 초기화 시킬때 활용됩니다.
// @AfterEach 적용
class DemoUtilsTest {
private DemoUtils demoUtils;
private List<String> testNameList;
@BeforeEach
void setupBeforeEach(){
demoUtils = new DemoUtils();
testNameList = new ArrayList<>();
System.out.println("call @BeforeEach");
}
@AfterEach
void afterEach(){
System.out.println("call @AfterEach : " + testNameList.get(0));
testNameList.remove(0);
}
@Test
void testEqualsAndNotEquals() {
System.out.println("call testEqualsAndNotEquals()");
testNameList.add("testEqualsAndNotEquals");
assertEquals(6, demoUtils.add(2, 4), "2 + 4 must be 6");
assertNotEquals(6, demoUtils.add(1, 9), "1 + 9 must not be 6");
}
@Test
void testNullAndNotNull() {
System.out.println("call testNullAndNotNull()");
testNameList.add("testNullAndNotNull");
assertNull(demoUtils.checkNull(null), "Object should be null");
assertNotNull(demoUtils.checkNull("dami"), "Object should not be null");
}
}
/* console 실행 결과
call @BeforeEach
call testNullAndNotNull()
call @AfterEach : testNullAndNotNull
call @BeforeEach
call testEqualsAndNotEquals()
call @AfterEach : testEqualsAndNotEquals
*/
예시를 위해 좀 억지로 만들어 보았는데 위와 같이 테스트에 사용된 컬렉션 및 데이터를 초기화 하거나 후처리를 하는 경우에 활용할 수 있습니다.
그런데 출력 결과를 보면 @BeforeEach와 @AfterEach는 각각의 테스트 실행전과 실행 후 계속해서 호출되는 것을 볼 수 있습니다.
모든 테스트 실행 전과 실행 후 단 한 번만 실행하고 싶은 코드가 있을 수도 있습니다. 테스트 실행 전 데이터베이스 커넥션을 얻거나 원격 서버에 연결하는 등, 테스트 실행 후 원격 서버와 연결 끊기 등..
Junit 에서 제공하는 @BeforeAll , @AfterAll 을 통해 간단하게 적용 할 수 있습니다.
@BeforeAll
모든 테스트 실행 전 단 한번 실행됩니다.
정적(static) 메서드여야 합니다.
@AfterAll
모든 테스트 실행 후 단 한번 실행됩니다.
정적(static) 메서드여야 합니다.
이번에도 다이어그램을 먼저 보여드리고 코드 예시를 보여드리겠습니다.
코드에 @BeforeAll 과 @AfterAll을 추가해 간단하게 실행 시점을 콘솔에 출력해보겠습니다.
class DemoUtilsTest {
private DemoUtils demoUtils;
private List<String> testNameList;
@BeforeEach
void setupBeforeEach(){
System.out.println("call @BeforeEach");
demoUtils = new DemoUtils();
testNameList = new ArrayList<>();
}
@AfterEach
void afterEach(){
System.out.println("call @AfterEach : " + testNameList.get(0));
testNameList.remove(0);
}
@BeforeAll
static void beforeAll(){
System.out.println("call @BeforeAll");
}
@AfterAll
static void afterAll(){
System.out.println("call @AfterAll");
}
@Test
void testEqualsAndNotEquals() {
System.out.println("call testEqualsAndNotEquals()");
testNameList.add("testEqualsAndNotEquals");
assertEquals(6, demoUtils.add(2, 4), "2 + 4 must be 6");
assertNotEquals(6, demoUtils.add(1, 9), "1 + 9 must not be 6");
}
@Test
void testNullAndNotNull() {
System.out.println("call testNullAndNotNull()");
testNameList.add("testNullAndNotNull");
assertNull(demoUtils.checkNull(null), "Object should be null");
assertNotNull(demoUtils.checkNull("dami"), "Object should not be null");
}
}
출력결과 테스트 실행 전 실행 후 단 한번만 호출 된 것을 확인할 수 있습니다.
/* 출력 결과
call @BeforeAll
call @BeforeEach
call testNullAndNotNull()
call @AfterEach : testNullAndNotNull
call @BeforeEach
call testEqualsAndNotEquals()
call @AfterEach : testEqualsAndNotEquals
call @AfterAll
*/
참고
@BeforeAll과 @AfterAll 사용 시 메서드를 static으로 선언하지 않으면 아래와 같은 에러가 발생합니다.
@AfterAll 에러 로그
org.junit.platform.commons.JUnitException: @AfterAll method 'void com.dami.unittest.demo.DemoUtilsTest.afterAll()' must be static unless the test class is annotated with @TestInstance(Lifecycle.PER_CLASS).
@BeforeAll 에러 로그
org.junit.platform.commons.JUnitException: @BeforeAll method 'void com.dami.unittest.demo.DemoUtilsTest.beforeAll()' must be static unless the test class is annotated with @TestInstance(Lifecycle.PER_CLASS).