Spring을 사용할 때 보통은 Junit을 사용해서 테스트를 실행하게 됩니다.
오늘은 테스트 코드 실행 시 어떠한 생명주기를 가지며 테스트를 실행하는지 알아보도록 하겠습니다.
Test LifeCycle Of Junit
@BeforeAll
BeforeAll 어노테이션은 클래스에 정의된 모든 테스트를 시작하기 전에 실행하는 메서드입니다.
BeforeAll 어노테이션이 붙은 메서드는 static 접근 제어자를 사용해야 합니다.
@BeforeEach
각각의 테스트를 진행하기 전에 실행하는 메서드 입니다.
BeforeEach 어노테이션이 붙은 메서드는 접근 제어자 static를 사용할 수 없습니다.
@AfterEach
각각의 테스트가 끝난 후 실행하는 메서드입니다.
Aftereach 어노테이션이 붙은 메서드는 접근 제어자 static를 사용할 수 없습니다.
@AfterAll
모든 테스트가 종료된 후 실행하는 메서드입니다.
AfterAll 어노테이션이 붙은 메서드는 static 접근 제어자를 사용해야 합니다.
public class TestInstanceLifeCycle {
@BeforeAll
static void beforeAll() {
System.out.println("BeforeAll 실행");
System.out.println("==============");
}
@BeforeEach
void beforeEach() {
System.out.println("BeforeEach 실행");
System.out.println("==============");
}
@AfterEach
void afterEach() {
System.out.println("==============");
System.out.println("AfterEach 실행");
System.out.println("==============");
}
@AfterAll
static void afterAll() {
System.out.println("AfterAll 실행");
}
@Test
void test1() {
System.out.println("test1 실행");
}
@Test
void test2() {
System.out.println("test2 실행");
}
}
다음과 같은 테스트 코드가 있을 때 실행결과는 다음과 같습니다.
BeforeAll 실행
==============
BeforeEach 실행
==============
test1 실행
==============
AfterEach 실행
==============
BeforeEach 실행
==============
test2 실행
==============
AfterEach 실행
==============
AfterAll 실행
Test Instance
테스트 메서드는 테스트 클래스의 인스턴스를 각각 생성합니다.
public class LifeCycleOfTest {
private int sum = 1; // 테스트 메서드를 실행하기 전에 테스트 클래스의 새 인스턴스를 만든다.
@Test
void addingTwo() {
this.sum += 2;
assertThat(this.sum).isEqualTo(3);
}
@Test
void addingThree() {
this.sum += 3;
assertThat(this.sum).isEqualTo(4);
}
}
다음과 같은 테스트 코드가 있을 때 테스트를 실행할 때마다 sum을 재할당 합니다.
그렇기 때문에 두 가지의 테스트코드는 성공합니다.
@TestInstance
TestInstance 어노테이션은 테스트 인스턴스의 생명주기를 클래스 단위로 가져가게끔 설정할 수 있습니다.@TestInstance(TestInstance.Lifecycle.PER_CLASS)
를 테스트 코드에 할당해 주면 됩니다.
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
public class LifeCycleOfTest {
private int sum = 1; // 인스턴스의 생명주기 => 클래스
private Person person = new Person("Tommy"); // 인스턴스의 생명주기 => 클래스
@Test
@Order(1)
void addingTwo() {
System.out.println("hashCode of person = " + person.hashCode());
this.sum += 2;
assertThat(this.sum).isEqualTo(3);
}
@Test
@Order(2)
void addingThree() {
System.out.println("hashCode of person = " + person.hashCode());
this.sum += 3;
assertThat(this.sum).isEqualTo(6);
}
}
해당 예제에서 인스턴스는 primitive 타입인 sum, 객체 타입인 person이 있습니다.
테스트 인스턴스의 생명주기가 클래스 단위로 가져가기 때문에 sum의 상태 및 person 객체의 상태가 유지됩니다.
그렇기 때문에 sum의 값 검증을 했을 때 테스트 코드가 성공하는 것을 알 수 있습니다.
person의 경우에도 새로 생성하지 않고 기존에 만든 인스턴스를 사용하기 때문에 hashCode가 동일함을 알 수 있습니다.
hashCode of person = 540325452
hashCode of person = 540325452
@MethodOrderer
테스트 코드는 기본적으로 테스트의 순서를 지정할 수 없습니다. 하지만 어떠한 경우에는 순차적인 테스트를 해야 할 때가 있습니다.
MethodOrderer 어노테이션을 사용한다면 테스트의 순서를 지정할 수 있습니다.
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
public class LifeCycleOfTest {
private int sum = 1; // 인스턴스의 생명주기 => 클래스
private Person person = new Person("Tommy"); // 인스턴스의 생명주기 => 클래스
@Test
@Order(1)
void addingTwo() {
System.out.println("hashCode of person = " + person.hashCode());
this.sum += 2;
assertThat(this.sum).isEqualTo(3);
}
@Test
@Order(2)
void addingThree() {
System.out.println("hashCode of person = " + person.hashCode());
this.sum += 3;
assertThat(this.sum).isEqualTo(6);
}
}
앞서 살펴본 예제와 동일한 예제입니다.
이 테스트의 경우 인스턴스의 상태가 유지된다는 가정하에 테스트를 진행했습니다.
만약 테스트가 addingThree() -> addingTwo()가 실행된다면 assertThat에서 원하는 결과가 다르기 때문에 테스트 결과가 실패하게 됩니다.
이러한 경우에 테스트의 실행 순서를 강제해야 합니다.
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
Order 어노테이션을 사용해 테스트 순서를 진행하겠다. 명시해 줍니다.
그 후 제가 의도하는 순서에 따라 @Order()를 사용해서 순서를 지정해 주면 됩니다.
'Spring' 카테고리의 다른 글
Spring, 그리고 Test (4) | 2023.10.11 |
---|---|
Spring MVC - 요청과 관련된 사용법 정리 (0) | 2023.07.06 |
NamedParameterJdbcTemplate (0) | 2023.07.01 |
JdbcTemplate 사용 방법에 대해서 (0) | 2023.07.01 |
프론트 컨트롤러 패턴은 무엇인가요? (0) | 2023.06.01 |