Java 언어에서 독립된 단위 테스트(Unit Test)를 지원해 주는 프레임워크를 의미한다.
JUnit 5의 경우 'Java8 이상 버전'부터 지원을 하며 JUnit Platform, Jupiter, Vintage 모듈이 결합된 형태이다.
Junit5 공식 홈페이지 https://junit.org/junit5/
JUnit5 = JUnit platform + JUnit Jupiter + JUnit Vintage
JUnit5에서는 Platform, TestEngine Interface, TestEngine, Jupiter, Vintage으로 구성된다.
구성 요소 | 설명 |
---|---|
JUnit Platform | - JUnit의 실행환경 - 다양한 TestEngine 구현체를 실행하고 테스트 결과를 보고하는 역할 수행 |
TestEngine Interface | - JUnit Platform에서 테스트 엔진을 정의하는 데 사용 - 이 인터페이스를 구현하여 사용자 정의 테스트 엔진 생성 가능 |
TestEngine | - JUnit Platform에서 테스트를 실행하는 데 사용되는 구현체 - 각 TestEngine 마다 특정한 테스트 프레임워크 또는 런처와 통합되어 동작 - 테스트 수명주기 관리, 테스트 실행, 결과 보고 등의 기능을 제공 |
JUnit Jupiter | - JUnit 5에서 제공되는 새로운 프레임워크 - 테스트 작성과 실행을 위한 새로운 기능과 어노테이션을 제공 - JUnit 4보다 더 강력하고 유연한 테스트 코드 작성이 가능 |
JUnit Vintage | - JUnit 4와의 하위 호환성을 제공하기 위한 모듈 - 이 모듈은 JUnit 4로 작성된 테스트를 JUnit 5 플랫폼에서 실행할 수 있도록 보장 |
JUnit Platform은 JUnit 테스트를 실행하는 데 사용되는 실행 환경을 의미한다. TestEngine Interface를 통하여 다른 TestEngine 구현체들과 상호작용하여 테스트를 실행하고 테스트 결과를 보고하는 역할을 수행하는 테스트 프레임워크이다. 테스트의 수행 과정은 발견, 실행, 결과 보고의 과정을 통해서 수행된다.
JUnit Platform에서 TestEngine Interface를 통해 테스트 엔진(Jupiter, Vintage)과 상호작용을 한다.
JUnit 3, 4, 5와 같은 테스트 프레임워크를 지원한다.
다양한 환경 및 설정에서 테스트를 실행 가능하다.
Test Framework와 TestEngine의 차이는?
[참고] TestEngine Interface의 주요 메서드
메서드 | 리턴 타입 | 설명 |
---|---|---|
discover() | void | - 테스트를 발견하고 고유한 ID를 부여하는 메서드 |
execute() | void | - 테스트를 실행하는 메서드 |
getId() | String | - 테스트 엔진의 고유 식별자를 반환하는 메서드 |
getGroupId() | String | - 테스트 엔진의 그룹 식별자를 반환하는 메서드 |
getVersion() | String | - 테스트 엔진의 버전을 반환하는 메서드 |
JUnit 5에서 제공되는 새로운 프레임워크를 의미하며 테스트 작성과 실행을 위한 기능은 어노테이션을 통해 사용
JUnit4 보다 강력하고 유연한 테스트 코드를 작성하도록 제공함
[참고] JUnit Jupiter의 주요 어노테이션
어노테이션 | 설명 |
---|---|
@Test | - 테스트 메서드를 정의하는 데 사용되는 어노테이션 - 이 어노테이션이 지정된 메서드는 JUnit Jupiter에서 테스트로 실행됨 |
@ParameterizedTest | - 매개변수화된 테스트를 정의하는 데 사용되는 어노테이션 - 이 어노테이션이 지정된 메서드는 여러 매개변수를 사용하여 반복적으로 실행 |
@BeforeEach | - 각 테스트 메서드마다 실행되기 전, 실행되는 코드를 정의하는 데 사용되는 어노테이션 |
@AfterEach | - 각 테스트 메서드마다 실행된 후, 실행되는 코드를 정의하는 데 사용되는 어노테이션 |
JUnit Jupiter 에서는 테스트 구성 및 프레임워크 확장을 위해 다음 어노테이션들을 지원한다.
어노테이션 | 설명 |
---|---|
@Test | 테스트 메소드임을 나타내는 어노테이션 |
@ParameterizedTest | 매개변수화된 테스트를 위한 어노테이션 |
@RepeatedTest | 반복적으로 실행되는 테스트를 위한 어노테이션 |
@TestFactory | 동적으로 테스트를 생성하는 팩토리 메소드를 정의하는 어노테이션 |
@TestTemplate | 테스트 템플릿을 정의하는 어노테이션 |
@TestClassOrder | 테스트 클래스의 실행 순서를 지정하는 어노테이션 |
@TestMethodOrder | 테스트 메소드의 실행 순서를 지정하는 어노테이션 |
@TestInstance | 테스트 인스턴스의 생명주기를 지정하는 어노테이션 |
@DisplayName | 테스트의 표시 이름을 설정하는 어노테이션 |
@DisplayNameGeneration | 테스트의 표시 이름을 동적으로 생성하는 어노테이션 |
@BeforeEach | 각 테스트 메소드 실행 전에 실행되는 메소드를 정의하는 어노테이션 |
@AfterEach | 각 테스트 메소드 실행 후에 실행되는 메소드를 정의하는 어노테이션 |
@BeforeAll | 모든 테스트 메소드 실행 전에 실행되는 메소드를 정의하는 어노테이션 |
@AfterAll | 모든 테스트 메소드 실행 후에 실행되는 메소드를 정의하는 어노테이션 |
@Nested | 중첩된 테스트 클래스를 정의하는 어노테이션 |
@Tag | 테스트를 그룹화하기 위한 태그를 지정하는 어노테이션 |
@Disabled | 비활성화된 테스트를 나타내는 어노테이션 |
@Timeout | 테스트의 제한 시간을 설정하는 어노테이션 |
@ExtendWith | 커스텀 확장을 적용하는 어노테이션 |
@RegisterExtension | 커스텀 확장을 등록하는 어노테이션 |
@TempDir | 테스트용 임시 디렉터리를 생성하는 어노테이션 |
Assertions
메서드를 제공 Assertions
는 테스트 코드의 예상 동작을 확인하는 데 도움import org.junit.jupiter.api.Assertions
패키지를 임포트 하여서 사용메서드 | 구분 | 설명 |
---|---|---|
assertEquals(expected, actual) | JUnit 4~ | 예상값과 실제값이 동일한지 확인 |
assertArrayEquals(expected, actual) | JUnit 4~ | 예상 배열과 실제 배열이 동일한지 확인 |
assertNull(object) | JUnit 4~ | 객체가 null인지 확인 |
assertNotNull(object) | JUnit 4~ | 객체가 null이 아닌지 확인 |
assertSame(expected, actual) | JUnit 4~ | 예상값과 실제값이 같은 객체인지 확인 |
assertNotSame(expected, actual) | JUnit 4~ | 예상값과 실제값이 다른 객체인지 확인 |
assertTrue(condition) | JUnit 4~ | 조건이 참인지 확인 |
assertFalse(condition) | JUnit 4~ | 조건이 거짓인지 확인 |
assertAll((Executable... executables) | JUnit 5 | 모든 단언문(assertion)이 성공하는지 확인 |
assertIterableEquals( Iterable expected, Iterable actual) | JUnit 5 | 예상 가능한 순서로 반복 가능한 항목이 동일한지 확인 |
assertLinesMatch( (List expectedLines, List actualLines) | JUnit 5 | 두 문자열 목록이 일치하는지 확인 |
assertNotEquals(Object unexpected, Object actual) | JUnit 5 | 예상값과 실제값이 동일하지 않은지 확인 |
assertThrows( Class expectedType, Executable executable) | JUnit 5 | 지정된 예외가 발생하는지 확인 |
assertTimeout( Duration timeout, Executable executable) | JUnit 5 | 주어진 시간 내에 작업이 완료되는지 확인 |
assertTimeoutPreemptively( Duration timeout, Executable executable) | JUnit 5 | 주어진 시간 내에 작업이 완료되는지 확인 단, 작업이 중단될 수 있음 |
JUnit을 구성한 클래스 기반으로 @Test
가 수행되는 기준으로 전후에 수행되는 라이프 사이클에 대해서 학습한다.
단계 | 설명 |
---|---|
Setup | - 각 테스트 메서드가 실행되기 전에 필요한 설정 작업을 수행 |
Test | - 실제 테스트가 진행되는 주요 단계이며, 각 테스트 메서드는 개별적으로 실행 - 코드의 예상 동작을 확인하기 위해 어설션(assertion) 또는 검증(verification)이 수행 |
Cleanup | - 각 테스트 메서드가 실행된 후 필요한 정리 작업을 수행 |
Suite-level setup and cleanup | - 테스트 스위트의 모든 테스트 메서드 실행 전후에 한 번씩 발생 - 테스트 스위트 전체에 적용되어야 하는 설정 또는 정리 작업을 수행하는 데 사용 |
@Test
를 선언한 순서에 따라 수행이 된다.@BeforeAll
] JUnit 클래스가 수행되면 최초 한번 @BeforeAll
어노테이션을 선언한 메서드가 실행됨@BeforeEach
] @Test
을 찾았다면 테스트 실행 전 @BeforeEach
을 선언한 메서드가 실행됨@Test
] @Test
를 선언한 메서드가 실행됨@AfterEach
] @Test
실행을 마치면 @AfterEach
를 선언한 메서드가 실행됨@Test
를 선언한 메서드가 있는지 찾으며 존재하면 (2. 과정)을 반복수행하며, 존재하지 않는 경우 (6. 과정)을 수행@AfterAll
] 실행할 @Test
가 존재하지 않는다면 @AfterAll
을 선언한 메서드를 수행함섹션 | 설명 |
---|---|
Given : 설정 | 테스트의 초기 상태 또는 사전 조건을 설정합니다. 입력 데이터나 테스트가 실행될 문맥을 지정 |
When : 동작 | 테스트되는 동작 또는 이벤트를 설명합니다. 테스트되는 특정 메서드나 동작 |
Then : 검증 | "When" 섹션에서 설명한 동작으로 인해 기대되는 결과 또는 동작을 정의 |
Assertion
)을 사용하여 검증import org.junit.jupiter.api.Test;
import java.util.ArrayList;
import static org.junit.jupiter.api.Assertions.*;
class MyTest {
@Test
void testListSize() {
// Given
ArrayList<String> list = new ArrayList<>();
// When
list.add("Apple");
list.add("Banana");
list.add("Orange");
// Then
assertEquals(3, list.size());
assertTrue(list.contains("Apple"));
assertFalse(list.isEmpty());
}
}
해당 패턴은 BDD의 테스트 시나리오를 작성하는 단계에서도 동일하게 적용이 가능하다. 참고 링크는 다음과 같다. https://adjh54.tistory.com/305
인기 있는 JUnit 명명 규칙은 다음을 참고한다. https://dzone.com/articles/7-popular-unit-test-naming
'메서드명_테스트대상상태_예상동작'
형식MethodName_StateUnderTest_ExpectedBehavior
'메소드명_테스트대상상태_예상동작'
형식으로 JUnit 메서드 명을 지정하는 방식이 전략에 대해서는 메소드 이름이 코드 리팩토링의 일부로 변경된다면 이 테스트 이름도 변경되어 나중에 이해하기 어려워진다는 반대 의견이 존재한다.
'메서드명_테스트대상상태_예상동작'
사용 예제- isAdult_AgeLessThan18_False
: 만약 나이가 18보다 작으면 성인이 아님 (False)을 반환하는 경우
- withdrawMoney_InvalidAccount_ExceptionThrown
: 잘못된 계정으로 출금 시 예외가 발생하는 경우
- admitStudent_MissingMandatoryFields_FailToAdmit
: 필수 입력 필드가 누락되었을 때 학생을 입학시키지 못하는 경우
'메서드명_예상동작_테스트대상상태 '
형식MethodName_ExpectedBehavior_StateUnderTest
'메서드명_예상동작_테스트대상상태'
형식으로 JUnit 메서드 명을 지정하는 방식조금 다른 방식으로 변경된 것이지만, 일부 개발자들은 이 명명 기법을 사용하는 것을 권장한다. 이 기법은 메서드 이름이 변경되면 이해하기 어려워진다는 단점이 있다.
'메서드명_예상동작_테스트대상상태'
사용 예제- isAdult_False_AgeLessThan18
: 만약 나이가 18보다 작으면 성인이 아님 (False)을 반환하는 경우
- withdrawMoney_ThrowsException_IfAccountIsInvalid
: 잘못된 계정으로 출금 시 예외가 발생하는 경우
- admitStudent_FailToAdmit_IfMandatoryFieldsAreMissing
: 필수 입력 필드가 누락되었을 때 학생을 입학시키지 못하는 경우
'test'
접두어 형식test [Feature being tested]
test
접두어 형식으로 JUnit 메서드 명을 지정하는 방식.test
접두어가 중복된다는 주장도 있지만, 일부 개발자들은 이 기법을 사용하는 것을 선호한다. 또한 SonarLint에 code smells를 피할 수 있다는 이유로 권장되는 방식이다.test [Feature being tested]
사용 예제- testIsNotAnAdultIfAgeLessThan18
: 만약 나이가 18보다 작으면 성인이 아님을 테스트합니다.
- testFailToWithdrawMoneyIfAccountIsInvalid
: 잘못된 계정으로 출금 시 실패하는 것을 테스트합니다.
- testStudentIsNotAdmittedIfMandatoryFieldsAreMissing
: 필수 입력 필드가 누락되었을 때 학생이 입학되지 않는 것을 테스트합니다.
Should_예상동작_테스트대상상태
형식Should_ExpectedBehavior_When_StateUnderTest
'Should_예상동작_When_테스트대상상태'
로 JUnit 메서드 명을 지정하는 방식Should_예상동작_테스트대상상태
사용 예제- Should_ThrowException_When_AgeLessThan18
: 만약 나이가 18보다 작으면 예외를 던져야 한다.
- Should_FailToWithdrawMoney_ForInvalidAccount
: 잘못된 계정일 경우 출금에 실패해야 한다.
- Should_FailToAdmit_IfMandatoryFieldsAreMissing
: 필수 입력 필드가 누락되었을 때 입학에 실패해야 한다.
When_테스트대상상태_Expect_예상동작
형식When_StateUnderTest_Expect_ExpectedBehavior
'When_테스트대상상태_Expect_예상동작'
으로 JUnit 메서드 명을 지정하는 방식입니다.When_테스트대상상태_Expect_예상동작
사용 예제- When_AgeLessThan18_Expect_isAdultAsFalse
: 만약 나이가 18보다 작으면 성인이 아님 (False)을 예상
- When_InvalidAccount_Expect_WithdrawMoneyToFail
: 잘못된 계정으로 출금 시 실패할 것을 예상
- When_MandatoryFieldsAreMissing_Expect_StudentAdmissionToFail
: 필수 입력 필드가 누락되었을 때 학생 입학이 실패할 것을 예상
Given_Preconditions_When_StateUnderTest_Then_ExpectedBehavior
이 접근 방식은 Behavior-Driven Development (BDD)의 일부로 개발된 명명 규칙에 기반을 두고 있다. 개별 테스트를 세 부분으로 나눠 사전 조건, 테스트 대상 상태 및 예상 동작을 위의 형식에 맞춰 작성한다.
Given_Preconditions_When_StateUnderTest_Then_ExpectedBehavior
사용 예제- Given_UserIsAuthenticated_When_InvalidAccountNumberIsUsedToWithdrawMoney_Then_TransactionsWillFail
: 사용자가 인증된 상태에서 잘못된 계정 번호를 사용하여 금액을 인출하면 거래가 실패할 것이다.