SpringBoot에서 JUnit5로 효율적인 단위 테스트 작성하기, Assertions로 값 검증하기

JUnit5 소개

JUnit은 자바 개발에서 단위 테스트를 작성하기 위한 표준 프레임워크입니다. JUnit을 사용하여 각각의 코드 조각을 테스트(단위 테스트)하고 그 결과를 검증할 수 있습니다. JUnit은 테스트 메서드를 정의하고 테스트 실행을 관리하는 데 도움을 줍니다. 

 

JUnit5는 다음 세 가지 구성 요소로 구성된 자바 단위 테스트 프레임워크입니다.

  1. JUnit Platform:
    JUnit 5의 기반을 형성하는 모듈입니다.
    테스트 실행 엔진(Test Execution Engine)을 포함하며, 다양한 테스트 프레임워크를 지원하고 확장성을 제공합니다.
    다양한 환경에서 테스트 실행을 지원하며, 새로운 테스트 엔진을 개발할 수 있습니다.
  2. JUnit Jupiter:
    JUnit 5의 새로운 테스트 API입니다.
    @Test, @BeforeEach, @AfterEach 등의 어노테이션을 제공하여 테스트를 작성하고 관리하는 데 사용됩니다.
    테스트의 라이프사이클 관리, 매개 변수화 테스트, 중첩 테스트 등의 현대적인 기능을 제공합니다.
    자바 8 이상의 버전에서 람다 표현식과 스트림 API를 활용하여 테스트를 작성할 수 있도록 설계되었습니다.
  3. JUnit Vintage:
    JUnit 3 및 JUnit 4와 호환성을 유지하기 위한 모듈입니다.
    JUnit 5 플랫폼 아래에서 기존의 JUnit 3 및 JUnit 4 스타일의 테스트를 실행할 수 있도록 지원합니다.
    이를 통해 기존의 테스트 코드를 JUnit 5 플랫폼에서도 계속해서 실행할 수 있습니다.

 

테스트 어노테이션

1. @Test

@Test
void testMethod() {
    // ...
}

메서드를 테스트 메서드로 지정합니다. 테스트 메서드는 `void` 반환 형식을 가져야 합니다.

 

2. @DisplayName

@DisplayName("커스텀 이름")
void testWithCustomName() {
    // Your test logic here
}

테스트 메서드 이름을 지정할 수 있습니다.

 

3. @ParameterizedTest

@ParameterizedTest
@ValueSource(ints = {1, 2, 3})
void testWithValueSource(int argument) {
    assertTrue(argument > 0);
}

매개 변수화된 테스트 메서드를 지정합니다. 여러 인수로 메서드를 실행할 수 있습니다.

 

4. @RepeatedTest

@RepeatedTest(10)
void repeatedTest() {
  System.out.println("Hello, Test!");
}

테스트를 반복 실행할 수 있습니다. 

 

5. @TestMethodOrder

@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
public class TestMethodOrderExample {

    @Test
    @Order(1)
    void firstTest() {
        System.out.println("First test");
    }

    @Test
    @Order(3)
    void thirdTest() {
        System.out.println("Third test");
    }

    @Test
    @Order(2)
    void secondTest() {
        System.out.println("Second test");
    }
}

@TestMethodOrder(MethodOrderer.OrderAnnotation.class) 어노테이션을 사용하여 @Order 어노테이션을 통해 순서를 지정한 순서대로 테스트 메서드가 실행됩니다.

 

6. @BeforeEach / @AfterEach

@BeforeEach
void setUp() {
    // 각 테스트 시작하기 전 실행
}

@AfterEach
void tearDown() {
    // 각 테스트 끝난 후 실행
}

각 테스트 메서드 실행 전/후에 실행됩니다.

 

7. @BeforeAll / @AfterAll

@BeforeAll
static void setUpBeforeAll() {
    // 모든 테스트 시작 하기 전 실행
}

@AfterAll
static void tearDownAfterAll() {
    // 모든 테스트 끝난 후 실행
}

모든 테스트 실행 전/후에 실행됩니다. 반드시 `static` 메서드여야 합니다.

 

8. @Nested

@Nested
class AdditionTests {
    @Test
    void testPositiveNumbers() { }
    
    @Test
    void testNegativeNumbers() { }
}

@Nested
class SubtractionTests {

    @Test
    void testPositiveNumbers() { }

    @Test
    void testNegativeNumbers() { }
}

테스트 클래스 내부에 중첩된(nested) 테스트 클래스를 정의할 때 사용됩니다. 해당 어노테이션을 사용하여 테스트 클래스를 모듈화하고 구조화할 수 있습니다. 

 

9. @Disabled

@Disabled
void disabledTest() {
}

특정 테스트를 비활성화시킵니다.

 

10. @Tag

@Tag("k-tag")
void testWithTag() {
}

태그를 지정하여 테스트 그룹을 만들 수 있습니다.  설정 파일 구성 시 지정한 태그를 통해 포함시킬 테스트 메서드와 제외시킬 테스트 메서드를 구분할 수 있습니다. 

 

11. @Timeout

@Test
@Timeout(5) // 초 단위
void testWithTimeout() {
}

 테스트가 지정된 시간 내에 완료되지 않으면 실패합니다. 

 

 

참고: Assertions

테스트 코드에서 예상한 결과와 실제 결과를 비교하고 검증하는데 사용되는 기능 또는 메서드 모음입니다. JUnit5를 사용하여 단위 테스트할 때 많이 사용되기 때문에 추가적으로 설명하도록 하겠습니다.  

 

 

  • assertEquals(expected, actual):
    예상한 값 expected와 실제 값 actual을 비교하고 두 값이 동일한지 확인합니다.
  • assertNotEquals(unexpected, actual):
    예상치 않은 값 unexpected와 실제 값 actual을 비교하고 두 값이 서로 다른지 확인합니다.
  • assertTrue(condition):
    주어진 조건 condition이 true인지 확인합니다. 조건이 true가 아니면 AssertionError가 발생합니다.
  • assertFalse(condition):
    주어진 조건 condition이 false인지 확인합니다. 조건이 false가 아니면 AssertionError가 발생합니다.
  • assertNotNull(object):
    주어진 객체 object가 null이 아닌지 확인합니다. 객체가 null이면 AssertionError가 발생합니다.
  • assertNull(object):
    주어진 객체 object가 null인지 확인합니다. 객체가 null이 아니면 AssertionError가 발생합니다.
  • assertArrayEquals(expectedArray, actualArray):
    예상한 배열 expectedArray과 실제 배열 actualArray을 비교하고 두 배열이 동일한지 확인합니다.
  • assertThrows(expectedExceptionType, executable):
    예외를 발생시키는 코드 블록 executable을 실행하고, 예상한 예외 유형 expectedExceptionType이 발생하는지 확인합니다. 예외가 발생하지 않거나 다른 유형의 예외가 발생하면 AssertionError가 발생합니다.
  • assertSame(expected, actual):
    예상한 객체 expected와 실제 객체 actual이 동일한 참조를 가리키는지 확인합니다.
  • assertNotSame(unexpected, actual): 
    예상치 않은 객체 unexpected와 실제 객체 actual이 서로 다른 참조를 가리키는지 확인합니다.
  • assertIterableEquals(expected, actual):
    예상한 Iterable expected와 실제 Iterable actual이 동일한 순서와 요소를 가지고 있는지 확인합니다.
  • assertLinesMatch(expected, actual):
    예상한 문자열 라인 목록 expected와 실제 문자열 라인 목록 actual이 일치하는지 확인합니다.
  • assertThat("Hello, World!", containsString("Hello")):
    문자열 포함하는지 확인합니다.
  • assertThat(actualNumber, greaterThan(5)):
    어떤 수보다 큰지 확인합니다. assertTrue를 사용할 수 있기 때문에 많이 쓰이진 않습니다.