본문 바로가기
Back-End (web)

[Kotlin][Mockito] IllegalStateException 에러

by 햄과함께 2019. 3. 5.
320x100

참고 원문 : Befriending Kotlin and Mockito

 

 

Test Code

@MockBean
lateinit var memberService: MemberService

@Test
fun Test() {
    // ....
    
    Mockito.`when`(memberService.getMemberId(any(MemberRequest::class.java)))
        .thenReturn(0)
}

 

MemberRequest를 파라미터로 하고 memberId(Int 형)를 반환하는 getMemberId 함수를 테스트해보았다.

 

memberService.getMemberId(any(MemberRequest::class.java)) 부분에서 에러.

 

 

Error

 
java.lang.IllegalStateException: any(MemberRequest::class.java) must not be null

org.mockito.exceptions.misusing.InvalidUseOfMatchersException: 
Misplaced or misused argument matcher detected here:

-> at ~~.Test.getMemberId(Test.kt:10)

You cannot use argument matchers outside of verification or stubbing.
Examples of correct usage of argument matchers:
    when(mock.get(anyInt())).thenReturn(null);
    doThrow(new RuntimeException()).when(mock).someVoidMethod(anyObject());
    verify(mock).someMethod(contains("foo"))

This message may appear after an NullPointerException if the last matcher is returning an object 
like any() but the stubbed method signature expect a primitive argument, in this case,
use primitive alternatives.
    when(mock.get(any())); // bad use, will raise NPE
    when(mock.get(anyInt())); // correct usage use

Also, this error might show up because you use argument matchers with methods that cannot be mocked.
Following methods *cannot* be stubbed/verified: final/private/equals()/hashCode().
Mocking methods declared on non-public parent classes is not supported.

왜 에러가 발생하는지는 위의 에러로그에서 알 수 있다.

when(mock.get(any())); // bad use, will raise NPE

any() 함수에서 null을 리턴하므로 에러가 발생한다.

kotlin class는 final이기 때문에 mocking이 불가능하다고 한다.

 

Solve

@MockBean
lateinit var memberService: MemberService

// add
private fun <T> any(): T {
    Mockito.any<T>()
    return null as T
}

@Test
fun Test() {
    // ....
    
    Mockito.`when`(memberService.getMemberId(any(MemberRequest::class.java)))
        .thenReturn(0)
}

별도의 라이브러리 추가없이 any() 함수를 재정의하여서 해결했다.

Generic을 사용해서 Null Object를 클래스 객체로 변환한다.

어차피 null as T 만 반환하는데 Mockito.any<T>() 가 있을 필요가 있나 싶은데 이게 없으면 에러가 난다. 

 


 

기타 [ Mockito-kotlin ]

 

https://github.com/nhaarman/mockito-kotlin

실제로 적용 해보지는 않았지만 mockito-kotlin 라이브러리란게 있다.

Mockito에서 any()와 같은 함수 호출 시 null을 반환해서 IllegalStateException 에러를 뱉는데 이를 해결하기 위해 actual instances를 생성해 반환해준다.

 

추가로 코틀린에서는 when(switch와 비슷한 기능)이 예약어이기 때문에 테스트코드 상에서 사용할 때에는 Mockito.`when` 으로 사용해야 한다.

mockito-kotlin 라이브러리에서는 이와 같은 경우를 피하기 위해 whenever으로 when을 사용할 수 있게 해준다.

320x100

댓글