Java_Hamcrest

Minki CHO·2023년 2월 2일
0

CodeStates

목록 보기
40/43

Hamcrest

Hamcrest
:JUnit 기반의 단위 테스트에서 사용할 수 있는 Assertion Framework

? Hamcrest 사용하는 이유?
:Assertion을 위한 매쳐Matcher가 자연스러운 문장으로 이어지므로 가독성이 향상됨
:테스트 실패 메시지를 이해하기 쉬움
:다양한 Matcher를 제공

JUnit Assertion을 사용한 단위 테스트에 Hamcrest Assertion 적용하기

ex1.
-ver Junit에서의 Assertion

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 assertionTest1() {
        String actual = "Hello, JUnit";
        String expected = "Hello, JUnit";

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

-ver Hamcrest의 Matcher

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

import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.is;

public class HelloHamcrestTest {

    @DisplayName("Hello Junit Test using hamcrest")
    @Test
    public void assertionTest1() {
        String expected = "Hello, JUnit";
        String actual = "Hello, JUnit";

        assertThat(actual, is(equalTo(expected)));  // 2)
    }
}

1) assertEquals(expected, actual);
:JUnit Assertion 기능 이용
:파라미터로 입력된 값의 변수 이름을 통해 대략적으로 어떤 검증을 하려는지 알 수 있으나 구체적인 의미는 유추하는 과정이 필요

2) assertThat(actual, is(equalTo(expected)));
:Hamcrest의 매쳐Matcher 이용
:위 코드는 assert that actual is equal to expected 라는 문장으로 자연스럽게 읽힘(결과값actual이 기대값expected과 같다는 것을 검증Assertion함)

-assetThat() 메서드의 파라미터
:첫번째 파라미터 :테스트 대상의 실제 결과 값
:두번째 파라미터 :기대하는 값, 이런 값일거라고 기대(예상)하는 값

ex2.
-ver Junit에서의 Assertion

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

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

public class HelloJunitTest {

    @DisplayName("Hello Junit Test")
    @Test
    public void assertionTest1() {
        String actual = "Hello, JUnit";
        String expected = "Hello, World";

        assertEquals(expected, actual);
    }
}

결과
:failed

expected: <Hello, World> but was: <Hello, JUnit>
Expected :Hello, World
Actual   :Hello, JUnit

-ver Hamcrest의 Matcher

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

import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.*;

public class HelloHamcrestTest {

    @DisplayName("Hello Junit Test using hamcrest")
    @Test
    public void assertionTest() {
        String expected = "Hello, World";
        String actual = "Hello, JUnit";

        assertThat(actual, is(equalTo(expected)));
    }
}

결과
:failed

Expected: is "Hello, World"
     but: was "Hello, JUnit"

:실행 결과도 하나의 문장으로 자연스럽게 읽혀짐

ex3.
-테스트 대상 클래스

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

-ver Junit에서의 Assertion

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 AssertionNullHamcrestTest {

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

-ver Hamcrest의 Matcher

import com.codestates.CryptoCurrency;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;

import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.*;

public class AssertionNullHamcrestTest {

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

        assertThat(currencyName, is(notNullValue()));   // 1)
//        assertThat(currencyName, is(nullValue()));    // 2)
    }

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

NotNull Test
:is(), notNullValue() 매쳐 사용

2) assertThat(currencyName, is(nullValue())) 주석 해제 시 결과는 아래와 같음

Expected: is null
     but: was "Ethereum"

ex4.
-ver Junit에서의 Assertion

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

:assertThrows() 이용해 "XRP" 존재하는지 여부를 확인하는 예외 발생 여부를 테스트

-ver Hamcrest의 Matcher

import com.codestates.CryptoCurrency;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;

import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.is;
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
import static org.junit.jupiter.api.Assertions.assertThrows;

public class AssertionExceptionHamcrestTest {

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

        assertThat(actualException.getClass(), is(NullPointerException.class));  // 2)
    }

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

:발생하는 예외가 NullPointerException인지 체크

but.
예외에 대한 테스트는 Hamcrest만으로 Assertion을 구성하기 힘듦
:1)과 같이 JUnit의 assertThrows() 메서드를 이용해 assertThrows() 리턴값을 전달받은 후
:2)와 같이 assertThat(actualException.getClass(),is(NullPointerExceptioin.class));를 통해 throw된 Exception 타입이 기대했던 Exception 타입과 일치하느지 추가로 검증 진행

profile
Developer

0개의 댓글