컴퓨터 프로그래밍/Spring

[Spring] 단위 테스트 프레임워크 JUnit5, Given-When-Then 패턴

한33 2024. 9. 9. 21:23

User Guide Link

https://junit.org/junit5/docs/current/user-guide/#writing-tests-annotations

Before - After

@BeforeEach
void setUp() {
    System.out.println("각각의 테스트 코드가 실행되기 전에 수행");
}

@AfterEach
void tearDown() {
    System.out.println("각각의 테스트 코드가 실행된 후에 수행\n");
}

@BeforeAll
static void beforeAll() {
    System.out.println("모든 테스트 코드가 실행되기 전에 최초로 수행\n");
}

@AfterAll
static void afterAll() {
    System.out.println("모든 테스트 코드가 수행된 후 마지막으로 수행");
}

@Test
void test1() {
    System.out.println("테스트 코드 작성 1");
}

@Test
void test2() {
    System.out.println("테스트 코드 작성 2");
}

 

  • @BeforeAll, @AfterAll 은 static 으로 메서드를 선언해준다.

테스트 꾸미기

@DisplayName

@Test
@DisplayName("테스트의 내용을 한 눈에 알아볼 수 있게 네이밍 해줄 때")
void test1() {
    System.out.println("테스트 내용 빠르게 파악");
}

 

test 에 대한 설명을 주석으로 할 필요 없이 @DisplayName 을 사용


@Nested

@Nested
@DisplayName("Test2 다른 주제")
class Test2 {
    @Test
    @DisplayName("Test2 - test1()")
    void test1() {
        System.out.println("Test2.test1");
    }

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

 

@Nested 로 그룹을 지어서 마찬가지로 class 를 이용해서 주제별로 묶을 수 있다.


@Order(1)

@Nested
@DisplayName("주제 별로 테스트를 그룹지어서 파악하기 좋습니다.")
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
class Test1 {

    @Order(1)
    @Test
    @DisplayName("Test1 클래스")
    void test() {
        System.out.println("\nTest1 클래스");
    }

    @Order(3)
    @Test
    @DisplayName("Test1 - test1()")
    void test1() {
        System.out.println("Test1.test1");
    }

    @Order(2)
    @Test
    @DisplayName("Test1 - test2()")
    void test2() {
        System.out.println("Test1.test2");
    }
}

  • 테스트를 메서드 단위로 순서를 매길 때는 @TestMethodOrder(MethodOrderer.OrderAnnotation.class) 애너테이션 설정
  • 그런 다음 원하는 순서에 맞게 메서드에 @Order(2) 애너테이션을 추가하고 () 괄호안에 순서를 입력

테스트 반복하기

@RepeatedTest

@RepeatedTest(value = 5, name = "반복 테스트 {currentRepetition} / {totalRepetitions}")
void repeatTest(RepetitionInfo info) {
    System.out.println("테스트 반복 : " + info.getCurrentRepetition() + " / " + info.getTotalRepetitions());
}

  • name 속성을 사용하여 네이밍
  • RepetitionInfo 값을 파라미터로 받아서 현재 반복 횟수와 총 횟수 값을 확인할 수 있음

@ParameterizedTest

@DisplayName("파라미터 값 활용하여 테스트 하기")
@ParameterizedTest
@ValueSource(ints = {1, 2, 3, 4, 5, 6, 7, 8, 9})
void parameterTest(int num) {
    System.out.println("5 * num = " + 5 * num);
}

  • @ValueSource(ints = {1, 2, 3, 4, 5, 6, 7, 8, 9})를 사용하여 파라미터 값을 전달 할 수 있음
    • 전달되는 파라미터 수 만큼 테스트 메서드가 수행됨.
    • int, String 등 여러 타입의 파라미터를 전달할 수 있음.
    • 향상된 for 문 느낌처럼 사용하면 될 듯함

Assertions

Assertions.assertEquals(expected, actual)

@Test
@DisplayName("assertEquals")
void test1() {
    Double result = calculator.operate(5, "/", 2);
    assertEquals(2.5, result);
}

@Test
@Disabled
@DisplayName("assertEquals - Supplier")
void test1_1() {
    Double result = calculator.operate(5, "/", 0);
    // 테스트 실패 시 메시지 출력 (new Supplier<String>())
    assertEquals(2.5, result, () -> "연산자 혹은 분모가 0이 아닌지 확인해보세요!");
}

@Test
@DisplayName("assertNotEquals")
void test1_2() {
    Double result = calculator.operate(5, "/", 0);
    assertNotEquals(2.5, result);
}
  • assertEquals() 메서드는 첫 번째 파라미터에 예상값을 넣고 두 번째 파라미터에 테스트 결과값(실제값)을 넣어줌
  • 예상값과 실제값이 다르면 테스트가 실패함
  • 3번째 파라미터 값에 람다식으로 메시지를 넣어두면 테스트 실패 시 해당 메시지가 출력됨. (new Supplier<String>())

Assertions.assertTrue(boolean)

@Test
@DisplayName("assertTrue 와 assertFalse")
void test2() {
    assertTrue(calculator.validateNum(9));
    assertFalse(calculator.validateNum(0));
}
  • assertTrue() 메서드는 해당 파라미터 값이 true인지 확인

Assertions.assertNotNull(actual)

@Test
@DisplayName("assertNotNull 과 assertNull")
void test3() {
    Double result1 = calculator.operate(5, "/", 2);
    assertNotNull(result1);
    Double result2 = calculator.operate(5, "/", 0);
    assertNull(result2);
}
  • assertNotNull() 메서드는 해당 파라미터 값이 null이 아님을 확인

Assertions.assertThrows(expectedType, executable)

@Test
@DisplayName("assertThrows")
void test4() {
    IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, () -> calculator.operate(5, "?", 2));
    assertEquals("잘못된 연산자입니다.", exception.getMessage());
}
  • assertThrows() 메서드는 첫 번째 파라미터에 예상하는 Exception 클래스 타입을 넣고 두 번째 파라미터에 실행 코드를 넣으면 됨.
  • 실행 코드의 결과가 예상한 해당 클래스 타입이라면 테스트에 성공.

Given - When - Then 패턴

@Test
@DisplayName("계산기 연산 성공 테스트")
void test1() {
    // given
    int num1 = 5;
    String op = "/";
    int num2 = 2;

    // when
    Double result = calculator.operate(num1, op, num2);

    // then
    assertNotNull(result);
    assertEquals(2.5, result);
}
@Test
@DisplayName("계산기 연산 실패 테스트 : 연산자가 잘못됐을 경우")
void test1_2() {
    // given
    int num1 = 5;
    String op = "?";
    int num2 = 2;

    // when - then
    IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, () -> calculator.operate(5, "?", 2));
    assertEquals("잘못된 연산자입니다.", exception.getMessage());
}