다음과 같은 JUnit 테스트 코드가 있다고 해보자.
import org.junit.jupiter.api.Test
class TestForTestInstance {
var number = 0
@Test
fun add1() {
number++
println("[add1] number is $number")
}
@Test
fun add2() {
number+=2
println("[add2] number is $number")
}
}
테스트를 진행하면 콘솔에 출력되는 number 값은 어떻게 될까?
테스트 순서를 정하지 않아 순서는 몰라도 결과적으로는 둘 중 하나는 number가 3으로 출력되어야 할 것 같다.
테스트를 실행시켜보면 다음과 같이 콘솔에 출력되는 것을 확인할 수 있다.
number 값이 테스트 후 롤백이라도 된 것처럼 number값이 예상한대로 출력되지 않는다.
(롤백이 된건 아니다 🤓)
위 상황을 이해하기 위해서는 테스트 인스턴스의 라이프 사이클을 설정하는 @TestInstance 라는 어노테이션에 대해 살펴볼 필요가 있다.
@TestInstance
@TestInstance의 주석을 살펴보면 다음과 같이 설명되어 있다.
TestInstance is a type-level annotation that is used to configure the lifecycle of test instances for the annotated test class or test interface.
If @TestInstance is not explicitly declared on a test class or on a test interface implemented by a test class, the lifecycle mode will implicitly default to PER_METHOD.
@TestInstance는 테스트 인스턴스의 라이프 사이클을 설정하는데 사용된다고 한다.
테스트 클래스에 @TestInstance가 명시적으로 지정되지 않은 경우, 기본적으로 PER_METHOD를 사용한다고 한다.
PER_METHOD는 Lifecycle enum 값으로 아래에 설명하도록 하겠다.
Lifecycle
Lifecycle은 @TestInstance java file 내에 선언된 enum으로 말그대로 테스트 인스턴스의 라이프 사이클을 지정하는 enum이다.
Lifecycle은 PER_METHOD, PER_CLASS가 있다.
Lifecycle.PER_METHOD
When using this mode, a new test instance will be created for each test method, test factory method, or test template method.
This mode is analogous to the behavior found in JUnit versions 1 through 4.
주석에서 볼 수 있듯, PER_METHOD 설정은 각 테스트 마다 테스트 인스턴스가 생성된다고 한다.
Lifecycle.PER_CLASS
When using this mode, a new test instance will be created once per test class.
PER_CLASS 설정은 테스트가 아니라 테스트 클래스 별로 테스트 인스턴스가 생성된다고 한다.
위에서 설명한 것 처럼 기본적으로 테스트 당 테스트 인스턴스가 생성되기 때문에,
처음 테스트 코드에 있었던 number 값은 테스트 별로 각자의 0인 number를 사용하기 때문에 3이라는 값이 나오지 않았던 것이다.
명확하게 확인하기 위해 다음과 같이 각 테스트에 println(this) 를 추가해보자.
import org.junit.jupiter.api.Test
class TestForTestInstance {
var number = 0
@Test
fun add1() {
number++
println("[add1] number is $number")
println(this)
}
@Test
fun add2() {
number+=2
println("[add2] number is $number")
println(this)
}
}
위와 같이 기본(PER_METHOD)적으로 다음과 같이 테스트 시 서로 다른 테스트 인스턴스를 사용하고 있음을 확인할 수 있다.
PER_CLASS로 설정하고 테스트를 다시 돌려보고 차이를 확인해보자.
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.TestInstance
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
class TestForTestInstance {
var number = 0
@Test
fun add1() {
number++
println("[add1] number is $number")
println(this)
}
@Test
fun add2() {
number+=2
println("[add2] number is $number")
println(this)
}
}
결과적으로 number는 3이 되었고 각 테스트가 같은 테스트 인스턴스를 사용하고 있음을 확인할 수 있다.
Lifecycle.PER_CLASS 는 언제 사용할까?
테스트 인스턴스를 생성하는데 비용이 많이 드는 경우(예를 들면 테스트 용 Docker Container를 실행한다던지)에 유용하다고 한다.
또 테스트 끼리는 상태를 공유하지 않고 서로 격리가 되어야 좋지만, 순서대로 상태 값을 다음 테스트로 전달해야하는 경우에 유용하다고 한다.
(참고: https://www.baeldung.com/junit-testinstance-annotation#test-instance-uses)
참고:
'Java & Kotlin > Java' 카테고리의 다른 글
[Java] List, Set, Map 구현체들 (0) | 2023.01.06 |
---|---|
BigDecimal이 소수를 다루는 방법 (0) | 2022.12.08 |
jabba global JDK 설정하기 (0) | 2022.04.09 |
gradle multi module test 속도를 높여보자 (with parallel) (1) | 2021.07.29 |
Servlet Filter의 response의 PrintWriter를 close 해야할까? (0) | 2021.02.24 |
댓글