티스토리 뷰

JUnit5 란?

JUnit이란 자바 프로그래밍 언어용 단위 테스트 프레임워크입니다.

SpringBoot 2.2.0 이전에는 JUnit4가 기본으로 설정되었지만, SpringBoot 2.2.0 버전부터는 JUnit5가 기본으로 설정됩니다.

JUnit5는 런타임 시 Java8 이상이 필요하며, Junit5를 사용하려면 Gradle 4.7 이상이 여야 합니다.

JUnit의 경우 Spring boot initializer에서 Spring-Web을 dependencies를 사용하게 되면 자동적으로 추가가 됩니다.

 

JUnit 5 = JUnit Platform + JUnit Jupiter + JUnit Vintage

 

  • JUnit  Platform : 테스트를 발견하고 테스트 계획을 생성하는 Test Engine API를 가지고 있습니다. Platform은 TestEngine을 통해서 테스트를 발견하고 실행하고 결과를 보고합니다.
  • JUnit Jupiter : Test Engine의 실제 구현체는 별도 모듈이며, 모듈 중 하나가 jupiter-engine입니다. 이 모듈은 jupiter-api를 사용해서 작성한 테스트 코드를 발견하고 실행합니다. Jupiter API는 JUnit 5에 새롭게 추가된 테스트 코드용 API로서, 개발자는 Jupiter API를 사용해서 테스트 코드를 작성할 수 있습니다
  • JUnit Vintage : JUnit 4 버전으로 작성한 테스트 코드를 실행할 때에는 vintage-engine 모듈을 사용합니다.

 

JUnit5 어노테이션 (Annotation) 알아보기
JUnit5 어노테이션 설명
@Test 테스트 Method임을 선언 / 정적 테스트
@ParameterizedTest 매개변수를 받는 테스트를 작성
@RepeatedTest 반복되는 테스트를 작성
@TestFactory @Test로 선언된 정적 테스트가 아닌 동적으로 테스트를 사용
@TestInstance 테스트 클래스의 생명주기를 설정
@TestTemplate 공급자에 의해 여러 번 호출될 수 있도록 설계된 테스트 케이스 템플릿임을 나타냄
@TestMethodOrder 테스트 메소드 실행 순서를 구성에 사용
@DisplayName 테스트 클래스 or 메소드의 사용자 정의 이름을 선언할 때 사용
@DisplayNameGeneration 이름 생성기를 선언함.
예를 들어 '_'를 공백 문자로 치환해주는 생성기가 있음. ex ) new_test -> new test
@BeforeEach 모든 테스트 실행 전에 실행할 테스트에 사용
@AfterEach 모든 테스트 실행 후에 실행한 테스트에 사용
@BeforeAll 현재 클래스를 실행하기 전 제일 먼저 실행할 테스트 작성 / static으로 선언
@AfterAll 현재 클래스 종료 후 해당 테스트를 실행 / static으로 선언
@Nested 클래스를 정적이 아닌 중첩 테스트 클래스임을 나타냄
@Tag 클래스 또는 메소드 레벨에서 태그를 선언할 때 사용
@Disabled 이 클래스나 테스트를 사용하지 않음
@Timeout 테스트 실행 시간을 선언 후 초과되면 실패하도록 설정
@ExtendWith 확장을 선언적으로 등록할 때 사용
@RegisterExtension 필드를 통해 프로그래밍 방식으로 확장을 등록할 때 사용
@TempDir 필드 주입 또는 매개변수 주입을 통해 임시 디렉토리를 제공하는데 사용

 

JUnit5 Assertions 알아보기
JUnit5 Assertions 설명
assertArrayEquals 예상 배열과 실제 배열이 동일한지 확인
배열이 같지 않으면 마지막 인자로 들어간 메세지가 출력됨

char[] val1 = { 'J', 'u', 'p', 'i', 't', 'e', 'r' };
char[] val2 = "Jupiter".toCharArray();
assertArrayEquals(val1, val2, "Array is different.");
assertEquals 두 값을 비교하여 일치 여부 판단

int val1 = 3 * 1;
int val2 = 3 * 5;
assertEquals(val1, val2);
assertTrue & assertFalse JUnit4 버전과 동일하며 BooleanSupplier도 사용 가능

BooleanSupplier condition = () -> 3 > 5;
assertFalse(val, "3 is not greater then 5");
assertNull & assertNotNull JUnit4 버전과 동일하며 객체의 null 여부 확인

assertNull(val, () -> "should be null");
assertSame & assertNotSame JUnit4 버전과 동일하며 예상되는 값과 실제 값이 동일한 객체를 참조하는지 확인

String val1 = "Java";
Optional<String> val2 = Optional.of(language);

assertSame(val1, val2.get());
fail 제공된 실패 메시지와 기본 원인으로 테스트에 실패
개발이 완료되지 않은 테스트를 표시하는 데 유용

fail("Fail Error");
assertAll - 모든 Assertion이 실행되고 실패가 함께 보고되는 그룹화된 Assertion
- MultipleFailureError에 대한 메시지 문자열에 포함될 제목과 실행 가능한 스트림을 허용
- 실행 파일 중 하나에서 OutOfMemoryError가 발생한 경우에만 중단됨
- 메소드 내에서 인자로 람다식을 사용
- 여러 개의 람다식이 동시에 실행됨

assertAll(
      "test",
      () -> assertEquals(15, 3 * 5, "15 is 3 times 5"),
      () -> assertEquals("java", "JAVA".toLowerCase()),
      () -> assertEquals(null, null, "null is equal to null")
    );
assertIterableEquals - 예상 반복 가능 항목과 실제 반복 가능 항목이 동일한지 확인
- 두 Iterable은 동일한 순서로 동일한 요소를 반환해야 함
- 두 Iterable이 동일한 유형일 필요는 없음
- 아래에서 서로 다른 유형의 두 목록(LinkedList 및 ArrayList)이 동일한지 확인

Iterable<String> val1 = new ArrayList<>(asList("Java", "Junit", "Test"));
Iterable<String> val2 = new LinkedList<>(asList("Java", "Junit", "Test"));

assertIterableEquals(val1, val2);
assertNotEquals 예상 값과 실제 값이 다름을 확인

Integer val = 5;
    
assertNotEquals(0, val, "The result cannot be 0");
assertLinesMatch - 예상 목록이 실제 목록과 일치하는지 확인
- assertEquals, assertIterableEquals와 다름
    > 예상 줄이 실제 줄과 같은지 확인
    > 같으면 다음 쌍으로 이동
    > String.matches() 메서드로 검사
    > fast-forward marker 확인
- 아래에서 두 목록에 일치하는 행이 있는지 검사

List<String> val1 = asList("Java", "\\d+", "JUnit");
List<String> val2 = asList("Java", "11", "JUnit");

assertLinesMatch(expected, actual);
assertThrows - 특정 예외가 발생하였는지 확인
- 첫 번째 인자는 확인할 예외 클래스
- 두 번째 인자는 테스트하려는 코드

Throwable exception = assertThrows(
      IllegalArgumentException.class, 
      () -> {
          throw new IllegalArgumentException("Exception message");
      }
    );
    assertEquals("Exception message", exception.getMessage());
assertTimeout
& assertTimeoutPreemptively
- 특정 시간 안에 실행이 끝나는지 확인
- 시간 내 실행이 끝나는지 여부 확인 시 : assertTimeout
- 지정한 시간 내 끝나지 않으면 바로 종료 : assertTimeoutPreemptively

assertTimeout(
      ofSeconds(2), 
      () -> {
        // code that requires less then 2 minutes to execute
        Thread.sleep(1000);
      }
    );

 

Given-When-Then

Given-When-Then는 테스트 코드를 작성하는 반 구조화(semi-structured) 된 방법입니다.

  • given은 테스트에서 구체화하고자 하는 행동을 시작하기 전에 테스트 상태를 설명하는 부분
  • when은 구체화하고자 하는 그 행동
  • then은 어떤 특정한 행동 때문에 발생할 거라고 예상되는 변화에 대해 설명하는 부분

 

SpringBoot Junit5 따라 하기

Junit5 사용을 위해 의존성 추가와 테스트 로직을 구현해보겠습니다.

Sources영역과 tests영역이 분리되어있으며, 구조는 동일하게 구성해 주는 게 좋습니다.

프로젝트 구조

 

build.gradle

tasks.named('test') {
	useJUnitPlatform()
}

testImplementation ('org.springframework.boot:spring-boot-starter-test') {
	exclude group: 'org.junit.vintage', module: 'junit-vintage-engine' //Junit4제외
}
testImplementation 'org.junit.jupiter:junit-jupiter-api:5.8.2'
testImplementation 'org.junit.jupiter:junit-jupiter-engine:5.8.2'
testImplementation 'org.junit.jupiter:junit-jupiter-params:5.8.2'

 

Repository Interface에서 "Ctrl+Shift + t"로 Test Class를 만들어 줍니다.

BoxOfficeRepository.java
Create Test

 

BoxOfficeRepositoryTest.java

package com.api.opendata.dao;

import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase;
import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;
import org.junit.jupiter.api.*;
import static org.assertj.core.api.Assertions.assertThat;
import com.api.opendata.model.boxoffice.MovieVO;
import java.util.List;
import java.util.stream.Collectors;

@DataJpaTest
@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE)
class BoxOfficeRepositoryTest {
    @Autowired
    private BoxOfficeRepository boxOfficeRepository;

    @BeforeAll
    static void beforeAll() {
        System.out.println("JUnit - @BeforeAll");
    }

    @AfterAll
    static void afterAll() {
        System.out.println("JUnit - @AfterAll");
    }

    @BeforeEach
    void beforeEach() {
        System.out.println("JUnit - @BeforeEach");
    }

    @AfterEach
    void afterEach() {
        System.out.println("JUnit - @AfterEach");
    }

    @Test
    void findAllTest() {
        //given
        List<MovieVO> movieList = boxOfficeRepository.findAll();

        //when
        List<MovieVO> actionList = movieList.stream().filter(f -> "액션".equals(f.getRepGenreNm())).collect(Collectors.toList());

        //then
        assertThat(actionList)
                .isNotEmpty()
                .hasSize(2);
    }

    @Test
    void test2() {
        System.out.println("JUnit - @Test test2");
    }

    @Test
    @Disabled
    void disabled_test() {
        System.out.println("JUnit - @Test @Disabled");
    }
}

 

  • Unit Test에 성공한 경우

Unit Test 성공화면

  • Unit Test에 실패한 경우

Unit Test 실패화면

 

movieList에는 총 4Row의 데이터가 있으며, 장르가 액션인 Row는 2개입니다.

hasSize에서 2로 했을 경우 일치하므로 성공하였지만, 2가 아닌 다른 값인 경우 일치하지 않으므로 실패하였습니다.

 

참고

https://junit.org/junit5/docs/current/user-guide/#overview

 

JUnit 5 User Guide

Although the JUnit Jupiter programming model and extension model do not support JUnit 4 features such as Rules and Runners natively, it is not expected that source code maintainers will need to update all of their existing tests, test extensions, and custo

junit.org

https://steady-coding.tistory.com/349

 

JUnit5 필수 개념 정리 (JAVA)

안녕하세요? 코딩중독입니다. 우테코를 진행하면서 JUnit5를 활용한 단위 테스트를 배우고 있는데, 관련된 JUnit5 문법을 정리하기 위해 포스팅을 작성합니다. 혹시나 미흡하거나 틀린 부분은 댓글

steady-coding.tistory.com

https://velog.io/@ynjch97/JUnit5-JUnit5-%EA%B5%AC%EC%84%B1-%EC%96%B4%EB%85%B8%ED%85%8C%EC%9D%B4%EC%85%98-Assertions-%EC%A0%95%EB%A6%AC

 

[JUnit5] JUnit5 구성, 어노테이션, Assertions 정리

JAVA 8 버전부터 사용 가능참고 사이트 https://steady-coding.tistory.com/349JUnit5는 JUnit Platform, JUnit Jupiter, JUnit Vintage가 결합한 형태JUnit PlatformJVM에서 테스트

velog.io

 

 

댓글
최근에 올라온 글
TAG
more
글 보관함
«   2024/11   »
1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30