[Springboot] 단위 테스트

·2023년 11월 1일
0

프로젝트 공부

목록 보기
31/33

테스트의 종류

테스트는 TDD와 단위 테스트(Unit Test)로 나눌 수 있다.

TDD

테스트가 주도하는 개발을 의미한다.
테스트 코드를 작성 후 테스트가 통과하면 코드에 참여시킨다

  • Red - 항상 실패하는 테스트를 먼저 작성하고
  • Green - 테스트가 통과하는 프로덕션 코드를 작성하고
  • Refactor - 테스트가 통과하면 프로덕션 코드를 리팩토링한다.

단위테스트

TDD의 첫 번째 단계인 기능 단위의 테스트 코드를 작성하는 것.
TDD와 달리 테스트 코드를 먼저 작성할 필요도, 리펙토링도 포함되지도 않는다.

오늘 작성할 내용은 단위테스트에 관한 것이다.

단위 테스트

단위테스트를 해야하는 이유

  1. 개발단계 초기에 문제를 발견하게 도와준다.
  2. 개발자가 나중에 코드를 리팩토링하거나 라이브러리 업그레이드 등에서 기존 기능이 올바르게 작동하는지 확인할 수 있다(ex. 회귀 테스트)
  3. 기능에 대한 불확실성을 감소시킬 수 있다.
  4. 시스템에 대한 실제 문서를 제공한다. 즉, 단위 테스트 자체가 문서로 사용할 수 있다.
  5. 빠른 피드백

⌨️테스트 작성

기본 구조

  • given : 이런 데이터가 주어졌을 때
  • when : 이런 함수를 실행하면
  • then : 이런 결과가 나와야 한다
//예시
import org.junit.jupiter.api.Test;

public class Example {

  @Test
  void test() {
    //given

    //when

    //then  }}

📌Junit5 어노테이션

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

📌Junit5 Assertions

assertEquals

두 값을 비교하여 일치 여부 판단
assertEquals("불일치", expected, actual); 실패 시 반환할 메세지 설정 가능

@Test
public void test() {
    String expected = "eunjy";
    String actual = "eunjy";

    assertEquals(expected, actual);
}

assertArrayEquals

두 배열을 비교하여 일치 여부 판단
두 배열이 모두 null이어도 동일한 것으로 간주함

@Test
public void test() {
    char[] expected = {'J','u','n','i','t'};
    char[] actual = "Junit".toCharArray();

    assertArrayEquals(expected, actual);
}

assertNotNull & assertNull

객체의 null 여부 확인

@Test
public void test() {
    Object car = null;
    
    assertNull("The car should be null", car);
}

assertNotSame & assertSame

두 변수가 동일한 객체를 참조하는지 확인

@Test
public void test() {
    Object cat = new Object();
    Object dog = new Object();

    assertNotSame(cat, dog);
}

assertTrue & assertFalse

특정 조건이 true인지 false인지 판단

@Test
public void test() {
    assertTrue("5 is greater then 4", 5 > 4);
    assertFalse("5 is not greater then 6", 5 > 6);
}

fail

AssertionFailedError를 발생시키는 테스트에 실패
실제 예외가 발생했는지 확인하거나, 개발 중에 테스트를 실패하게 만들고 싶을 때 사용

@Test
public void test() {
    try {
        methodThatShouldThrowException();
        fail("Exception not thrown");
    } catch (UnsupportedOperationException e) {
        assertEquals("Operation Not Supported", e.getMessage());
    }
}

assertAll

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

@Test
public void test() {
    assertAll(
      "heading",
      () -> assertEquals(4, 2 * 2, "4 is 2 times 2"),
      () -> assertEquals("java", "JAVA".toLowerCase()),
      () -> assertEquals(null, null, "null is equal to null")
    );
}

assertIterableEquals

예상 반복 가능 항목과 실제 반복 가능 항목이 동일한지 확인
두 Iterable은 동일한 순서로 동일한 요소를 반환해야 함
두 Iterable이 동일한 유형일 필요는 없음
아래에서 서로 다른 유형의 두 목록(LinkedList 및 ArrayList)이 동일한지 확인

@Test
public void test() {
    Iterable<String> al = new ArrayList<>(asList("Java", "Junit", "Test"));
    Iterable<String> ll = new LinkedList<>(asList("Java", "Junit", "Test"));

    assertIterableEquals(al, ll);
}

assertLinesMatch

예상 목록이 실제 목록과 일치하는지 확인
assertEquals, assertIterableEquals와 다름
예상 줄이 실제 줄과 같은지 확인
같으면 다음 쌍으로 이동
String.matches() 메서드로 검사
fast-forward marker 확인
아래에서 두 목록에 일치하는 행이 있는지 검사

@Test
public void test() {
    List<String> expected = asList("Java", "\\d+", "JUnit");
    List<String> actual = asList("Java", "11", "JUnit");

    assertLinesMatch(expected, actual);
}

assertNotEquals

예상 값과 실제 값이 다름을 확인

@Test
public void test() {
    Integer value = 5; // result of an algorithm
    
    assertNotEquals(0, value, "The result cannot be 0");
}

assertThrows

특정 예외가 발생하였는지 확인
첫 번째 인자는 확인할 예외 클래스
두 번째 인자는 테스트하려는 코드

@Test
void test() {
    Throwable exception = assertThrows(
      IllegalArgumentException.class, 
      () -> {
          throw new IllegalArgumentException("Exception message");
      }
    );
    assertEquals("Exception message", exception.getMessage());
}
@Test
    void test() {
        Exception exception = assertThrows(ArithmeticException.class, () ->
            calculator.divide(1, 0));
        assertEquals("/ by zero", exception.getMessage());
    }

assertTimeout & assertTimeoutPreemptively

특정 시간 안에 실행이 끝나는지 확인
시간 내 실행이 끝나는지 여부 확인 시 : assertTimeout
지정한 시간 내 끝나지 않으면 바로 종료 : assertTimeoutPreemptively

@Test
public void test() {
    assertTimeout(
      ofSeconds(2), 
      () -> {
        // code that requires less then 2 minutes to execute
        Thread.sleep(1000);
      }
    );
}
profile
개발자가 되고싶은 낭랑 24세

0개의 댓글

관련 채용 정보