Java_JUnit

Minki CHO·2023년 1월 31일
0

CodeStates

목록 보기
39/43

JUnit

? JUnit이란?
:Java 언어로 만들어진 애플리케이션을 테스트하기 위한 오픈소스 테스트 프레임워크
:사실상 Java의 표준 테스트 프레임워크임

JUnit 기본 작성법

1 JUnit을 사용한 테스트 케이스의 기본 주고

import org.junit.jupiter.api.Test;

public class JunitDefaultStructure {
		// 1)
    @Test
    public void test1() {
        // 테스트 하고자 하는 대상에 대한 테스트 로직 작성
    }

		// 2)
    @Test
    public void test2() {
        // 테스트 하고자 하는 대상에 대한 테스트 로직 작성
    }

		// 3)
    @Test
    public void test3() {
        // 테스트 하고자 하는 대상에 대한 테스트 로직 작성
    }
}

:애플리케이션에서 테스트하고자 하는 대상Target이 있으면,
-public void test1(){...} 같은 void 타입의 메서드를 만들고
-@Test 애너테이션을 추가함
-내부에 테스트 하고자 하는 대상에 대한 테스트 로직을 작성

2 Assertion 메서드 사용하기
(Assertion = 예상하는 결과 값이 참true이길 바라는 논리적인 표현)
:Assertion 관련 다양한 메서드를 사용해서 테스트 대상에 대한 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")  // 1)
    @Test
    public void assertionTest() {
        String expected = "Hello, JUnit";
        String actual = "Hello, JUnit";

        assertEquals(expected, actual); // 2)
    }
}

1) @DisplayName("Hello JUnit Test")
:테스트 케이스 실행 시, 실행 결과 창에 표시되는 이름을 지정

:실행 결과에 "Hello JUnit Test" 명시됨

2) assertEquals(expected, actual)
:기대하는 문자열expected과 실제 결과값actual이 일치하는지 검증
결과

:테스트 결과가 성공Passed인 경우 초록색 체크 아이콘 표시

:테스트 결과가 실패failed인 경우 X 체크 아이콘 표시 및 왜 실패했는지에 대한 설명 명시됨

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

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

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

:assertNotNull()
: 첫번째 파라미터는 테스트 대상 객체, 두번째 파라미터는 테스트에 실패했을 때 표시할 메시지

1) assertNotNull(currencyName, "should be not null")
:currencyName :테스트 대상 객체
:"should be not null" :테스트 실패 시 표시할 메시지/null일 때 표시할 메시지
결과

passed

:"ETH"에 해당하는 암호화폐 이름이 map에 저장되어 있어 passed 임

(참고)CryptoCurrency 클래스 코드

import java.util.HashMap;
import java.util.Map;

public class CryptoCurrency {
    public static Map<String, String> map = new HashMap<>();

    static {
        map.put("BTC", "Bitcoin");
        map.put("ETH", "Ethereum");
        map.put("ADA", "ADA");
        map.put("POT", "Polkadot");
    }
}

-assertThrows(): 예외 테스트

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() {
        // 1)
        assertThrows(NullPointerException.class, () -> getCryptoCurrency("XRP"));
    }

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

:getCryptoCurrency() 호출 시, NullPointerException 발생 여부 테스트

:assertThrows()
: 첫번째 파라미터에는 발생이 기대되는 예외 클래스, 두번째 파라미터의 람다 표현식에서는 테스트 대상 메서드 호출

1) assertThrows(NullPointerException.class, () -> getCryptoCurrency("XRP"))
:NullPointerException 예외가 발생할 것으로 예상
:getCryptoCurrency() 메서드 호출
:파라미터로 전달한 "XRP"라는 키에 해당하는 암호화폐가 있는지 map에서 찾음
:map에 "XRP" 존재하지 않으므로
:map에서 반환된 값은 null
:반환된 null인 상태에서 toUpperCase() 호출 후 대문자 변환하려함
:NullPointerException 발생
결과

passed

:NullPointerException이 발생할 것이라고 기대했고, NullPointerException이 발생하였음으로 passed임

3 테스트 케이스 실행 전, 전처리
:테스트 케이스 실행 전, 어떤 객체나 값에 대한 초기화 작업 등의 전체리 과정이 필요한 경우가 있음
:이 경우 JUit에서 사용할 수 있는 애너테이션 = @BeforeEach와 @BeforeAll()

-@BeforeEach: 테스트 케이스 실행될 때마다 먼저 실행되어 초기화 적업 등 진행 가능

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

// 1)
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 애너테이션이 추가된 init() 메서드

모든 테스트 케이스 메서드 실행 시 결과

Pre-processing before each test case
Pre-processing before each test case

:init() 메서드가 총 2번 실행됨

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

ex.

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

import java.util.HashMap;
import java.util.Map;

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

public class BeforeEach2Test {
    private Map<String, String> map;

    @BeforeEach
    public void init() {
        map = new HashMap<>();
        map.put("BTC", "Bitcoin");
        map.put("ETH", "Ethereum");
        map.put("ADA", "ADA");
        map.put("POT", "Polkadot");
    }

    @DisplayName("Test case 1")
    @Test
    public void beforeEachTest() {
        map.put("XRP", "Ripple");
        assertDoesNotThrow(() -> getCryptoCurrency("XRP"));
    }

    @DisplayName("Test case 2")
    @Test
    public void beforeEachTest2() {
        System.out.println(map);
        assertDoesNotThrow(() -> getCryptoCurrency("XRP"));
    }

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

결과

Test case1 - passed
Test case2 - failed

Test case1 실행
map.put("XRP", "Ripple")
:assertDoesNotThrow()로 Assertion 하기 전에 map에 "XRP"값 추가
assertDoesNotThrow(() -> getCryptoCurrency("XRP"))
(assertDoesNotThrow() :예외가 발생하지 않는다고 기대하는 Assertion 메서드)
:map에 "XRP" 값 존재 -> 예외 발생하지 않음
:예상expect-assertDoesNotThrow()로 예외가 발생하지 않음
:결과actual-예외 발생하지 않음
:테스트 결과-성공/passed

Test case2 실행되기 전 init() 메서드 호출
Test case2 실행
System.out.println(map)
:map 출력
assertDoesNotThrow(() -> getCryptoCurrency("XRP"))
(assertDoesNotThrow() :예외가 발생하지 않는다고 기대하는 Assertion 메서드)
:map에 "XRP" 값 추가하지 않아 존재하지 않음 -> NullpointerException 예외 발생
:예상expect-assertDoesNotThrow()로 예외가 발생하지 않음
:결과actual-NullpointerException 예외 발생
:테스트 결과-실패/failed

-@BeforeAll() :테스트 케이스를 한꺼번에 실행 시, 테스트 케이스 실행되기 전 딱 한번만 초기화 작업 할 수 있게 함

public class BeforeAllTest {
    private static Map<String, String> map;

    @BeforeAll
    public static void initAll() {
        map = new HashMap<>();
        map.put("BTC", "Bitcoin");
        map.put("ETH", "Ethereum");
        map.put("ADA", "ADA");
        map.put("POT", "Polkadot");
        map.put("XRP", "Ripple");

        System.out.println("initialize Crypto Currency map");
    }

    @DisplayName("Test case 1")
    @Test
    public void beforeEachTest() {
        assertDoesNotThrow(() -> getCryptoCurrency("XRP"));
    }

    @DisplayName("Test case 2")
    @Test
    public void beforeEachTest2() {
        assertDoesNotThrow(() -> getCryptoCurrency("ADA"));
    }

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

결과

Test case1 - passed
Test case2 - passed
initialize Crypto Currency map

:@BeforeAll 애너테이션을 사용하여 map 객체를 한번만 초기화함
:따라서 두 테스트 케이스 모두 passed임과 동시에
System.out.println("initialize Crypto Currency map") 실행으로
initialize Crypto Currency map 한번 출력됨

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

@BeforeAll
    public static void initAll() {...}
```)

4 테스트 케이스 실행 후, 후처리
:테스트 케이스 실행이 끝난 시점에 후처리를 할 수 있는 애너테이션 = @AfterEach와 @AfterAll()
:@BeforeEach와 @BeforeAl()과 동작 방식은 동일, 호출되는 시점만 반대임

5 Assumption을 이용한 조건부 테스트
:JUnit 5의 Assumption 기능 사용 시, 특정 환경에서만 테스트 케이스가 실행될 수 있도록 할 수 있음

ex.

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

import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.junit.jupiter.api.Assumptions.assumeTrue;

public class AssumptionTest {
    @DisplayName("Assumption Test")
    @Test
    public void assumptionTest() {
        // 1)
        assumeTrue(System.getProperty("os.name").startsWith("Windows"));
//        assumeTrue(System.getProperty("os.name").startsWith("Linux")); // 2)
        System.out.println("execute?");
        assertTrue(processOnlyWindowsTask());
    }

    private boolean processOnlyWindowsTask() {
        return true;
    }
}

assumeTrue() 메서드
:파라미터로 입력된 값이 true이면, 나머지 아래 로직을 실행

:테스트 케이스를 실행하는 PC의 운영체제가 Windows일 경우,
assumeTrue() 메서드의 파라미터 값 = true

"assumeTrue(): 특정 OS 환경 등의 특정 조건에서 선택적인 테스트가 필요할 때 유용하게 사용할 수 있음"

핵심
:JUnit으로 테스트 케이스를 작성하기 위해서는 기본적으로 @Test 애너테이션 추가해야함

profile
Developer

0개의 댓글