Android/Test

assertThat

봄석 2019. 10. 4. 16:26

assertThat알아보기

 JUnit을 활용한 테스트에서는 assertThat 구문을 활용하여 코드의 길이를 줄이면서도

읽혀지는 코드를 작성할 수 있도록 도와줍니다.

즉 assertThat을 잘 사용하면 개발자의 의도를 보다 명확하게 드러낼 수 있는 큰 장점을 얻어갈 수 있을 것입니다.

 

 

 

 

assertThat사용법

assertThat은

assertThat(T actual, Matcher<? super T> matcher)

위와 같은 형태로 메소드를 사용하여, 두 값을 비교할 수 있습니다.

첫번째 파라미터는 비교 대상의 실제값을 

두번째 파라미터로는 비교로직이 담긴 Matcher가 사용되게됩니다.

 

ex)

대표적인 매쳐인  Matcher is를 사용한 예입니다.

is 는 첫번쟤 파라미터 (acture)와 자기 자신의 파라미터가 동일한지 여부를 체크합니다.

@Test
fun addTest() {
    val result = 4 + 6
    Assert.assertThat(result, `is`(10))
}

 위의 코드에서 보다시피  is를 사용하여 A is B와 같이 읽혀지는 코드를 작성할 수 있게 됩니다.

 

 

JUnit 기본 제공 매쳐

위에서 소개한 is 이외에도 Junit에서는 상황에 맞는 다양한 매쳐를 지원하며 필요에 따라서 매쳐를 새롭게 구현하여 사용할 수 있습니다.

매쳐들을 순서대로 나열하여 여러 매쳐를 한번에 사용할 수 있도록 지원합니다.

아래는 앞의 문자열이 Test로 시작되지 않는지 여부를 확인하는 예시입니다.

@Test
fun `start word "Game" Test`() {
	assertThat("Sample string.", `is`(not(startsWith("Game"))))
	assertThat("Game Play.", `is`(startsWith("Game")))
}

 

 

Junit 기본 지원 매쳐들

JUnit은 아래와 같은 매쳐를 기본적으로 제공한다. JUnit에서 제공하는 매쳐는 org.hamcrest.CoreMatchers 클래스에 선언된 메서드를 통해 사용할 수 있다.

  • allOf
    • 내부에 선언된 모든 매쳐가 정상일 경우 통과한다.
    • assertThat("myValue", allOf(startsWith("my"), containsString("Val”)))
  • anyOf
    • 내부에 선언된 매쳐중 하나 이상 통과할 경우 통과한다.
    • assertThat("myValue", anyOf(startsWith("foo"), containsString("Val”)))
  • both
    • both A and B 형식으로 matcher를 사용할 수 있게 해 준다.
    • A, B 매쳐 둘다 통과할 경우 테스트가 성공한다.
    • assertThat("fab", both(containsString("a")).and(containsString(“b”)))
  • either
    • either A or B 형식으로 matcher를 사용할 수 있게 해 준다.
    • A, B 매쳐 둘중 하나가 성공할 경우 테스트가 성공한다.
    • assertThat("fan", either(containsString(“a”)).or(containsString(“b”)))
  • describedAs
    • 매쳐내부의 메시지를 변경할 수 있다.
    • assertThat (new BigDecimal(“32123”), describedAs("a big decimal equal to %0", equalTo(myBigDecimal), myBigDecimal.toPlainString()));
  • everyItem
    • 배열이나 리스트를 순회하며 매쳐가 실행된다.
    • assertThat(Arrays.asList("bar", "baz"), everyItem(startsWith("ba”)));
  • is
    • is는 두가지 용도로 사용할 수 있다.
    • A is B와 같이 비교값이 서로 같은지 여부를 확인할 경우
      • assertThat("Simple Text", is("Simple Text"));
      • 이경우 assertThat("Simple Text", is(equalTo("Simple Text")))와 동일하게 사용할 수 있다.
    • 다른 매쳐를 꾸며주는 용도로 사용. 매쳐에는 영향을 끼치지 않으며, 조금 더 표현력이 있도록 변경하여 준다.
      • assertThat("Simple Text", is(not("simpleText")));
      • 위의 경우 is가 빠지더라도 문제없이 작동된다. 하지만 is가 있음으로써 쉽게 읽혀지는 테스트 코드가 된다.
  • isA
    • 비교되는 값이 특정 클래스일 경우 테스트가 통과된다. is(instanceOf(SomeClass.class))와 동일하다.
    • assertThat(cheese, isA(Cheddar.class))
  • anything
    • 항상 true를 반환하는 매쳐
  • hasItem
    • 배열에서 매쳐가 통과하는 값이 하나 이상이 있는지 여부를 검사한다.
    • assertThat(Arrays.asList("foo", "bar"), hasItem("bar"))
  • hasItems
    • 배열에서 매쳐리스트에 선언된 값들 모두가 하나 이상 있는지 여부를 검사한다.
    • assertThat(Arrays.asList("foo", "bar", "baz"), hasItems("baz", "foo"))
  • equalTo
    • 두 값이 같은지 여부를 체크한다. is와 동일하게 사용할 수 있다.
    • assertThat("foo", equalTo("foo"));
  • any
    • 비교값이 매쳐의 타입과 동일한지 여부를 체크한다. instanceOf와는 다르게 매쳐의 값은 앞서 비교값의 타입의 자식만 비교할 수 있다.
    • assertThat(new Canoe(), instanceOf(Canoe.class));
  • instanceOf
    • 비교값이 매쳐의 타입과 동일한지 여부를 체크한다. any와는 다르게 매쳐의 값은 비교값과 연관없는 경우에도 사용할 수 있다.
    • assertThat(new Canoe(), instanceOf(Paddlable.class));
  • not
    • is와 동일하게 두가지 경우로 사용할 수 있다.
    • 내부에 매쳐를 선언할 경우 내부 매쳐의결과를 뒤집는다.
      • assertThat(cheese, is(not(equalTo(smelly))))
    • not뒤에 값이 나올 경우, 같지 않을 경우 테스트가 통과한다.
      • assertThat("Test", not("tEST"));
  • nullValue
    • 비교값이 null일경우 테스트가 통과한다.
    • assertThat(cheese, is(nullValue())
  • notNullValue
    • 비교값이 null이 아닐경우 테스트가 통과한다.
    • assertThat(cheese, is(notNullValue()))
  • sameInstance
    • 비교매쳐의 값과 같은 인스턴스일 경우 테스트가 통과한다. theInstance 와 동일
    • assertThat("Test", not(sameInstance("not Same Instance")));
  • theInstance
    • 비교매쳐의 값과 같은 인스턴스일 경우 테스트가 통과한다. sameInstance 와 동일
    • assertThat("Test", not(sameInstance("not Same Instance")));
  • containsString
    • 특정 문자열이 있는지를 검사한다.
    • assertThat("myStringOfNote", containsString("ring"));
  • startsWith
    • 특정 문자열로 시작하는지를 검사한다.
    • assertThat("myStringOfNote", startsWith("my"))
  • endsWith
    • 특정 문자열로 종료되는지를 검사한다.
    • assertThat("myStringOfNote", endsWith("Note"))

 

matcher 직접 정의하기

5의 배수인지를 확인하는 매쳐를

확장하여 아래와 같이 사용할 수 있는 커스텀 매쳐를 만들어보겠습니다.

   @Test
    fun `Junit customMatcher divisorOfFive`() {
        assertThat(15, `is`(divisorOfFive()))
    }

    private fun divisorOfFive(): TypeSafeMatcher<Int> {
        return object : TypeSafeMatcher<Int>() {
            override fun describeTo(description: Description?) {
                description?.appendValue("5의 배수여부 확인")
            }

            override fun matchesSafely(number: Int?): Boolean {
                return (number ?: 0) % 5 == 0
            }
        }
    }

matchesSafely함수안에 비교로직을 작성하고,

describeTo 함수안에 로직이 false 시에 나올 에러문구를 작성합니다.