본문 바로가기

TIL

TIL 240613 단위 테스트

단위 테스트

- 작은 단위로 쪼개서 각 단위가 정확하게 동작하는지를 검사하는 테스트 기법

- 빠르게 작성할 수 있고 문제 발생 시 어느 부분이 잘 못 되었는지를 빠르고 정확하게 확인할 수 있다는 장점

 

JUnit5

자바프로그래밍 언어용 단위 테스트 프레임워크

 

 Before-After 

@BeforeEach

 // Generate -> SetupMethod

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

각각의 테스트 코드가 실행되기 전에 수행되는 메서드를 만들어 줍니다.

 

@AfterEach

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

각각의 테스트 코드가 실행된 후에 수행되는 메서드를 만들어 줍니다.

 

@BeforeAll

@BeforeAll
static void beforeAll() {
    System.out.println("모든 테스트 코드가 실행되기 전에 최초로 수행\n");
}
  • 모든 테스트 코드가 수행되기 전에 최초로 수행되는 메서드를 만들어 줍니다.
  • static 메서드로 만들어야합니다.

@AfterAll

@AfterAll
static void afterAll() {
    System.out.println("모든 테스트 코드가 수행된 후 마지막으로 수행");
}
  • 모든 테스트 코드가 수행된 후 마지막으로 수행되는 메서드를 만들어 줍니다.
  • static 메서드로 만들어야합니다.

 

테스트 꾸미기

@DisplayName

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

@Nested

@Nested
@DisplayName("주제 별로 테스트를 그룹지어서 파악하기 좋습니다.")
class Test1 {
    @Test
    @DisplayName("Test1 - test1()")
    void test1() {
        System.out.println("Test1.test1");
    }

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

@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");
    }
}

 

@Order

@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());
}
  • @RepeatedTest를 사용하여 해당 테스트 메서드를 반복할 수 있습니다.
  • 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);
}
  • @ParameterizedTest를 사용하여 파라미터를 받아 테스트할 수 있는 메서드를 만들 수 있습니다.
  • @ValueSource(ints = {1, 2, 3, 4, 5, 6, 7, 8, 9})를 사용하여 파라미터 값을 전달 할 수 있습니다.
    • 전달되는 파라미터 수 만큼 테스트 메서드가 수행됩니다.
    • int, String 등 여러 타입의 파라미터를 전달할 수 있습니다.

 

Assertions

 Calculator

public class Calculator {
    public Double operate(double num1, String op, double num2) {
        switch (op) {
            case "*":
                return num1 * num2;
            case "/":
                if (validateNum(num2)) {
                    return num1 / num2;
                } else {
                    return null;
                }
            case "+":
                return num1 + num2;
            case "-":
                return num1 - num2;
            default:
                throw new IllegalArgumentException("잘못된 연산자입니다.");
        }
    }

    public boolean validateNum(double num) {
        if (num == 0) {
            return false;
        } else {
            return true;
        }
    }
}

 

AssertionTest

package com.sparta.junit5practice;

import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;

import static org.junit.jupiter.api.Assertions.*;

public class AssertionTest {

    Calculator calculator;
    //alt+insert - > setUp
    @BeforeEach
    void setUp() {
        calculator = new Calculator();
    }

	//test1~ 1_2 Assertions.assertEquals(expected, actual)
    /* - assertEquals() 메서드는 첫 번째 파라미터에 예상값을 넣고 두 번째 파라미터에 테스트 결과값(실제값)을 넣어줍니다.
       - 예상값과 실제값이 다르면 테스트가 실패합니다.
       - 3번째 파라미터 값에 람다식으로 메시지를 넣어두면 테스트 실패 시 해당 메시지가 출력됩니다. (`new Supplier<String>()`)
    */
    @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);
    }

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

	//Assertions.assertNotNull(actual)
    //assertNotNull()메서드는 해당 파라미터 값이 null이 아님을 확인
    @Test
    @DisplayName("assertNotNull 과 assertNull")
    void test3() {
        Double result1 = calculator.operate(5, "/", 2);
        assertNotNull(result1);
        Double result2 = calculator.operate(5, "/", 0);
        assertNull(result2);
    }
    
    //Assertions.assertThrows(expectedType, executable)
    //assertThrows()메서드는 첫 번째 파라미터에 예상하는 Exception 클래스 타입을 넣고 두 번째 파라미터에 실행 코드를 넣으면 된다
    @Test
    @DisplayName("assertThrows")
    void test4() {
        IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, () -> calculator.operate(5, "?", 2));
        assertEquals("잘못된 연산자입니다.", exception.getMessage());
    }
}

 

Given - When - Then

- Test Code 스타일을 표현하는 방식

 

Given

  • 테스트 하고자하는 대상을 실제로 실행하기 전에 테스트에 필요한 값(상태)을 미리 선언해 둡니다.

When

  • 테스트 하고자하는 대상을 실제로 실행 시킵니다.

Then

  • 어떤 특정한 행동(테스트 대상 실행) 때문에 발생할거라고 예상되는 결과에 대해 예측하고 맞는지 확인합니다.

 

패턴 연습하기

더보기

class CalculatorTest {

    Calculator calculator;

    @BeforeEach
    void setUp() {
        calculator = new Calculator();
    }

    @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("계산기 연산 실패 테스트 : 분모가 0일 경우")
    void test1_1() {
        // given
        int num1 = 5;
        String op = "/";
        int num2 = 0;

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

        // then
        assertNull(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());
    }
}

 

 

'TIL' 카테고리의 다른 글

TIL 240617 과제 피드백 AOP  (0) 2024.06.18
TIL 240614 Mockito, 통합테스트  (0) 2024.06.17
TIL 240612 카카오 로그인  (1) 2024.06.13
TIL 240611 3조 KPT 회고  (0) 2024.06.12
TIL 240610 예외 처리 변경  (0) 2024.06.11