[TDD] JUnit5 단위테스팅

무1민·2023년 8월 21일
0

TDD

목록 보기
1/1

JUnit의 등장 배경

JUnit은 자바 테스트 프레임워크다.
JUnit 등장 이전에 main에서 테스트를 했었고 많은 문제가 있었다.

main의 문제점

  • 구현 코드와 테스트 코드가 클래스 하나에 존재한다. 따라서 클래스 크기가 커지고, 복잡도가 증가한다.
  • 테스트 코드가 실 서비스에 같이 배포된다.
  • 메인 함수 하나에서 여러 개의 기능을 테스트 함으로써 복잡도가 증가한다.
  • 함수 이름을 통해 어떤 부분을 테스트하는지에 대한 의도를 드러내기 힘들다.
  • 테스트 결과를 사람이 수동으로 확인한다.

JUnit5 기본 Annotation

  • @Test : 테스트 메소드를 선언하기 위해 사용한다.
  • @ParameterizedTest : @Test와 달리 테스트 메서드가 인자를 받을 수 있도록 한다.
  • @DisplayName : 테스트 클래스나 테스트 메소드에 일므을 붙여줄 때 사용한다.
  • @Nested : test 클래스 안에 Nested 테스트 클래스를 작성할 때 사용되며, static이 아닌 중첩 클래스, 즉 Inner 클래스여야 한다.
  • @Tag : 테스트를 필터링할 때 사용한다. 클래스 또는 메소드 레벨에 사용한다.
  • @Disabled : 테스트 클래스나, 메소드의 테스트를 비활성화 한다.
  • @Timeout : 주어진 시간안에 테스트가 끝나지 않으면 실패한다.

라이프 사이클 메소드 Annotation

테스트 메소드가 실행되기 전/후에 실행되는 메소드

  • @BeforeEach : 각각 테스트 메소드가 실행되기 전에 실행되어야 하는 메소드를 명시해준다.
    @Test, @RepeatedTest, @ParameterizedTest, @TestFactory가 붙은 테스트 메소드가 실행하기 전에 실행된다.
  • @BeforeAll : @BeforeEach 는 각 테스트 메소드마다 실행되지만, 이 어노테이션은 테스트가 시작하기 전 딱 한 번만 실행된다.
  • @AfterEach, @AfterAll : 마찬가지다.

예)

@BeforeEach
void setUp() {
    numbers = new HashSet<>();
    numbers.add(1);
    numbers.add(1);
    numbers.add(3);
    numbers.add(2);
}

@Test
void setSizeTest() {
   assertThat(numbers.size()).isEqualTo(3);
}

@ParameterizedTest
@ValueSource(ints = {1, 2, 3})
void setContainTest(int number) {      
    assertThat(numbers.contains(number)).isTrue();
}

검증을 위한 테스트 코드 작성

@Test
void setSizeTest(){
	numbers = new HashSet<>();
    numbers.add(1);
    numbers.add(1);
    numbers.add(3);
    numbers.add(2);

}

검증 코드 작성하기(Assertion)

Assertions의 종류는 아래 2가지가 있으며,

  • import org.assertj.core.api.Assertions;
  • import org.junit.jupiter.api.Assertions;
    가독성을 위해 위에 있는 Assertions 사용 권장
  • assertThat()
    파라미터를 검증할 때 사용
@Test
void setSizeTest(){
	numbers = new HashSet<>();
    numbers.add(1);
    numbers.add(1);
    numbers.add(3);
    numbers.add(2);
    
    //검증 코드 추가 numbers.size()가 3과 동일하면 true 반환
    Assertions.assertThat(numbers.size()).isEqualTo(3);

}

@ParameterizedTest로 인자 넘기기

인자를 획득하기 위해 @ValueSource 등의 어노테이션을 추가로 요구한다.

@ValueSource
ValueSource는 원시 자료형의 배열을 메서드에 전달하고 전달된 배열의 크기만큼 테스트를 반복하여 실행한다.

// @ValueSource는 문자열, 정수 등, 원시 자료형의 배열을 메서드에 전달할 수 있다.
@ParameterizedTest
@ValueSource(ints = {1, 2, 3})
void setContainTest(int number) {
numbers = new HashSet<>();
numbers.add(1);
numbers.add(1);
numbers.add(3);
numbers.add(2);

assertThat(numbers.contains(number)).isTrue();
}

코드는 3회 실행되고 number에 1,2,3이 한번씩 들어갈때 검증된다.

@ParameterizedTest
@ValueSource(strings = { "Hello", "World" })
void testWithStringParameter(String argument) {
    assertNotNull(argument);
}

단순히 argument가 Null이 아닌지 검증

@CsvSource
한번에 여러 값들을 배열로 넘길 때 사용한다.
기본적으로 쉼표가 열 구분자이고, delimiter 속성을 사용하여 사용자가 정의할 수 있다.

@ParameterizedTest
@CsvSource({"test,TEST", "tEst,TEST", "Java,JAVA"})
//@CsvSource({"test:TEST", "tEst:TEST", "Java:JAVA"}, delimiter = ':')
void toUpperCaseValue(String input, String expected) {
    String actualValue = input.toUpperCase();
    assertThat(actualValue).isEqualTo(expected);
}

@MethodSource
복잡한 argument를 전달할 때 사용한다.
스트림 형태가 대부분이지만 리스트와 같은 컬렉션도 가능하다.

스트림 형태로 String과 boolean이 argument로 넘어오도록 provideStringsForIsBlank() 메서드를 정의하고 메서드를 @MethodSource의 이름으로 입력한다.

@ParameterizedTest
@MethodSource("provideStringsForIsBlank")
void methodSourceTest(String input, boolean expected) {
    assertEquals(expected, Strings.isBlank(input));
}

이름이 입력되지 않는다면 테스트 메소드의 이름인 methodSourceTest라는 메소드를 클래스 내부에서 찾게 된다.

private static Stream<Arguments> provideStringsForIsBlank() {
    return Stream.of(
      Arguments.of(null, true),
      Arguments.of("", true),
      Arguments.of("  ", true),
      Arguments.of("not blank", false)
    );
}

@NullSource
파라미터로 단순히 Null값을 넘겨준다.

@ParameterizedTest
@NullSource
void isBlank_ShouldReturnTrueForNullInputs(String input) {
    assertTrue(Strings.isBlank(input));
}
profile
야호

0개의 댓글