JUnit을 사용한 단위 테스트

Backend kwon·2023년 10월 12일
0

⚫ 단위 테스트를 위한 FIRST 원칙

  • Fast(빠르게) : 일반적으로 작성한 테스트 케이스는 빨라야 한다는 의미입니다.

  • Independent(독립적으로) : 각각의 테스트 케이스는 독립적이어야 한다는 의미입니다.
    예를 들어, A라는 테스트 케이스를 먼저 실행시킨 후에 다음으로 B라는 테스트 케이스를 실행시켰더니 테스트에 실패하게 된다면 테스트 케이스끼리 독립적이지 않은 것입니다.

  • Repeatable(반복 가능하도록) : 테스트 케이스는 어떤 환경에서도 반복해서 실행이 가능해야 된다는 의미입니다. 로컬 환경이나 서버 환경에서 실행하든 반복해서 같은 결과를 확인할 수 있어야 합니다.

  • Self-validating(셀프 검증이 되도록) : 단위 테스트는 성공 또는 실패라는 자체 검증 결과를 보여주어야 한다는 의미입니다.

  • Timely(시기적절하게) : 단위 테스트는 테스트하려는 기능 구현을 하기 직전에 작성해야 한다는 의미입니다.

 

⚫ Given-When-Then 표현 스타일

테스트 케이스의 가독성을 높이기 위해 given - when - then 표현 방법을 사용하는 것은 테스트 케이스를 작성하는데 유용한 방법입니다.

  • Given
    : 테스트를 위한 준비 과정을 명시할 수 있습니다.
    : 테스트에 필요한 전제 조건들이 포함된다고 보면 됩니다.
    : 테스트 대상에 전달되는 입력 값(테스트 데이터) 역시 Given에 포함됩니다.

  • When
    : 테스트할 동작(대상)을 지정합니다.
    : 단위 테스트에서는 일반적으로 메서드 호출을 통해 테스트를 진행하므로 한두 줄 정도로 작성이 끝나는 부분입니다.

  • Then
    : 테스트의 결과를 검증하는 영역입니다.
    : 일반적으로 예상하는 값(expected)과 테스트 대상 메서드의 동작 수행 결과(actual) 값을 비교해서 기대한 대로 동작을 수행하는지 검증(Assertion)하는 코드들이 포함됩니다.

 

⚫ JUnit이란?

JUnit은 Java 언어로 만들어진 애플리케이션을 테스트하기 위한 오픈 소스 테스트 프레임워크로서 사실상 Java의 표준 테스트 프레임워크라고 봐도 무방합니다.

🟩Assertion 메서드 사용

  • assertEquals() : 기대하는 값과 실제 결과 값이 같은지를 검증
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;

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

public class HelloJUnitTest {
    @DisplayName("Hello JUnit Test")  
    @Test
    public void assertionTest() {
        String expected = "Hello, JUnit";
        String actual = "Hello, JUnit";

        assertEquals(expected, actual); 
    }
}

 

  • assertNotNull() : Null 여부 테스트
import com.codestates.CryptoCurrency;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;

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

public class AssertionNotNullTest {

    @DisplayName("AssertionNull() Test")
    @Test
    public void assertNotNullTest() {
        String currencyName = getCryptoCurrency("ETH");

			
        assertNotNull(currencyName, "should be not null");
    }

    private String getCryptoCurrency(String unit) {
        return CryptoCurrency.map.get(unit);
    }
}

assertNotNull() 메서드의 첫 번째 파라미터는 테스트 대상 객체이고, 두 번째 파라미터는 테스트에 실패했을 때, 표시할 메시지입니다.

 

  • assertThrows() : 예외(Exception) 테스트
import com.codestates.CryptoCurrency;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;

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

public class AssertionExceptionTest {

    @DisplayName("throws NullPointerException when map.get()")
    @Test
    public void assertionThrowExceptionTest() {
        
        assertThrows(NullPointerException.class, () -> getCryptoCurrency("XRP"));
    }

    private String getCryptoCurrency(String unit) {
        return CryptoCurrency.map.get(unit).toUpperCase();
    }
}

getCryptoCurrency() 메서드를 호출했을 때, NullPointerException이 발생하는지 테스트하고 있습니다.
assertThrows()의 첫 번째 파라미터에는 발생이 기대되는 예외 클래스를 입력하고, 두 번째 파라미터인 람다 표현식에서는 테스트 대상 메서드를 호출하면 됩니다.

 

  • assertDoesNotThrow() : 예외가 발생하지 않는다고 기대하는 Assertion 메서드
assertDoesNotThrow(() -> getCryptoCurrency("XRP"));

 

🟩테스트 케이스 실행 전, 전 처리

  • @BeforeEach
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;


public class BeforeEach1Test {

    @BeforeEach
    public void init() {
        System.out.println("Pre-processing before each test case");
    }

    @DisplayName("@BeforeEach Test1")
    @Test
    public void beforeEachTest() {

    }

    @DisplayName("@BeforeEach Test2")
    @Test
    public void beforeEachTest2() {

    }
}

@BeforeEach 애너테이션을 추가한 메서드는 테스트 케이스가 각각 실행될 때마다 테스트 케이스 실행 직전에 먼저 실행되어 초기화 작업 등을 진행할 수 있습니다.

 

  • @BeforeAll
    테스트 케이스가 실행되기 전에 딱 한 번만 초기화 작업을 할 수 있도록 해주는 애너테이션입니다.

@BeforeAll 애너테이션을 추가한 메서드는 정적 메서드(static method)여야 합니다.

참고) 테스트 케이스 실행 후, 후처리

@AfterEach, @AfterAll로 앞서 @BeforeEach, @BeforeAll과 동작 방식이 같습니다.

 

🟩Assumption을 이용한 조건부 테스트

예를들어

public class AssumptionTest {
    @DisplayName("Assumption Test")
    @Test
    public void assumptionTest() {
       
        assumeTrue(System.getProperty("os.name").startsWith("Windows"));

        System.out.println("execute?");
        assertTrue(processOnlyWindowsTask());
    }

    private boolean processOnlyWindowsTask() {
        return true;
    }
}

위 코드에서 assumetrue() 값이 true이면 아래 로직을 실행하고 아니라면 실행되지 않습니다.

assumeTrue()는 특정 OS 환경 등의 특정 조건에서 선택적인 테스트가 필요하다면 유용하게 사용할 수 있는 JUnit 5의 API입니다.

profile
백엔드개발자를 향해서

0개의 댓글