Android/Test

Mockito-Kotlin Sample로 자세히 알아보기

봄석 2019. 10. 28. 17:06

Mockito-Kotlin Sample로 자세히 알아보기

#Mockito Features에 대한 문서를 글쓴이가 Kotlin으로 해석한 샘플입니다. 

틀린 것이나 좀 더 나은 코드가 있다면 댓글로 남겨주시면 감사하겠습니다 :)

 

#Mockito Features 원문

https://www.javadoc.io/static/org.mockito/mockito-core/3.1.0/org/mockito/Mockito.html

 

 

contents

 

 

1.  Mock객체의 동작(Behavior)을 검증해보기

 @Test
    fun `mock_will_memorize_all_interaction`() {

        val mockedList = mock<MutableList<String>>()

        mockedList.add("one")
        mockedList.clear()

        //검증하기 , mock은 모든 상호작용을 기억하고 있습니다.
        //사용자는 mock의 어떤 메소드가 실행되었는지 선택적으로 검증 가능합니다.
        verify(mockedList).add("one")
        verify(mockedList).clear()


        //검증 실패 케이 -add("two")가 호출되지않았으므로 실패
        //verify(mockedList).add("two")
    }

mock객체는 add() , clear() 같은 객체에 대한 상호작용에 대해서 기억하고 있습니다.

verify()를 이용하여 상호작용에 대하여 검증 가능합니다.

 

상호작용이 일어나지 않은 add("two")를 검증하면 테스트 실패합니다.

 

 

 

 

2. stubbing은 어떻게 하는 거지?

stub은 테스트에서 호출된 요청에 대해 미리 준비해둔 결과를 제공합니다.

  @Test(expected = RuntimeException::class)
    fun `how to stubbing`() {
        // interface 뿐 아니라 구체 클래스도 mock으로 만들 수 있습니다.
        val mockedList = mock<LinkedList<String>>()


        //stubbing
        whenever(mockedList[0]).thenReturn("first")
        whenever(mockedList[1]).thenThrow(RuntimeException())


        println(mockedList[0])  //첫 번째 element를 출력합니다.
        println(mockedList[1])  //RuntimeException occurred
        println(mockedList[999]) //999 element는 stub 되지않았으므로 null 출력합니다.


        // stubbing 된 부분이 호출되는지 확인할 수 있긴 하지만 불필요한 일입니다.
        // 만일 코드에서 get(0)의 리턴값을 확인하려고 하면, 다른 어딘가에서 테스트가 깨집니다.
        // 만일 코드에서 get(0)의 리턴값에 대해 관심이 없다면, stubbing되지 않았어야 합니다.
        verify(mockedList)[0]
    }

Interface뿐만 아니라 구체 클래스(구현이 있는 클래스)도  mock으로 만들 수 있습니다.

mockedList.get(0)은 "first"를 리턴하도록 stub 하고

mockedList.get(1)은 RuntimeException을 얻도록 stub 합니다.

mocekdList.get(999)는 stub 되지 않았으므로  null을 얻습니다.

 

 

 

 

3. Argument Matchers

@Test
    fun `argument_matcher`() {
        val mockedStringList =
            mock<LinkedList<String>>()  //val mockedIntList:LinkedList<Int> = mock()

        val mockedFloatList = mock<LinkedList<Float>> {
            on { this[ArgumentMatchers.anyInt()] } doReturn 3f
        }

        //내장된 argument matcher인 anyInt()를 이용한 stubbing
        // 모든 Integer 타입 매개변수를 받을 경우 "element"를 돌려줍니다.
        whenever(mockedStringList[ArgumentMatchers.anyInt()]).thenReturn("elements")

        println(mockedStringList[2])
        println(mockedFloatList[3])
        println(mockedFloatList[3])
    }

LinkedList <String>  mock 객체와 LinkedList <Float> mock객체를 만듭니다.

LinkedList <Float> 객체는 mock객체로 만들면서 바로 on { } doReturn을 이용하여 Stubbing 하여 줍니다.

 

on { this[ArgumentMatchers.anyInt()] } doReturn 3f

위의 코드는 this.get(anyInt())

즉 어떤 Int형 숫자를 넣든 간에

doReturn 3f 

 

3f를 반환합니다.

 

아래의 whenever도 마 찬자기로 mockedStringList.get(anyInt()) 

어떤 Int형 숫자를 넣든 간에

thenReturn "elements"

elements라는 스트링을 반환합니다.

 

즉 , Argument Matcher를 이용하면 임의의 인자 값을 지정할 수 있습니다.

예를 들어, 임의의 정수 값을 인자로 전달받은 메서드 호출을

when()과 verify()에서 표현하고 싶다면 다음과 같이 Matchers.anyInt() 메서드를 사용하면 됩니다.

 

Matchers 클래스는 anyInt() 뿐만 아니라 anyString(), anyDouble(), anyLong(), anyList(), anyMap() 등의 메서드를 제공하는데, 이들 메서드에 대한 자세한 내용은 아래 공식 document를 보는 것을 추천드립니다.

https://javadoc.io/static/org.mockito/mockito-core/3.1.0/org/mockito/ArgumentMatchers.html

 

ArgumentMatchers (Mockito 3.1.0 API)

Any char or non-null Character. Since Mockito 2.1.0, only allow valued Character, thus null is not anymore a valid value. As primitive wrappers are nullable, the suggested API to match null wrapper would be isNull(). We felt this change would make tests ha

javadoc.io

그리고 만약 여러 인자에 , agument matcher를 사용한다면 

모든 인자를 agument matcher로 사용해야만 합니다. 

 

세 개의 인자가를  stub으로 넣어주어야 할 때 2개는 anyXXX()로 임의의 값을 

나머지 1개의 인자는 특정 값으로  명시하고 싶다면 아래와 같이 지정합니다.

 

 

 @Test
    fun `verify_eq`() {
        val mock = mock<TestClass>()

        whenever(
            mock.someMethod(
                ArgumentMatchers.anyString(),
                ArgumentMatchers.anyString(),
                eq("3")
            )
        ).thenReturn("firstArgument secondArgument 3")

        println(mock.someMethod("1", "2", "3"))

        //인자 중 한가지라도 Argument Matcher를 사용하면 나머지 인자에 대해서도 Matcher를 사용해야 한다.
        //인자 중 특정한 값을 명시해야한다면 eq()를 사용한다
        verify(mock).someMethod(ArgumentMatchers.anyString(), ArgumentMatchers.anyString(), eq("3"))
        /** error
         * verify(mock).someMethod(ArgumentMatchers.anyInt(),ArgumentMatchers.anyString(), "3")
         * */
    }

위의 코드처럼 

두 개의 인자에 a mrguatcher를 사용하고 , 나머지 1개의 인자를 특정값으로 사용하고 싶다면 eq()를 사용하여 인자 값을 넣어줍니다.

 

주석의 내용을 보면 , eq()를 쓰지 않으면 에러가 발생합니다.

 

 

 

 

4. 몇 번 호출됐는지 / 최소한 한 번 호출됐는지 / 호출되지 않았는지 확인하기

verity으로 검증할 때 해당 내용이 몇 번 호출되었는지,

최소한 한번 호출되었는지 , 호출되지 않았는지도 검증할 수 있습니다.

verify의 2번째 인자(파라미터)로 넣어서 설정합니다.

 

  • atLeastOnece() : 적어도 한번 수행했는지 검증
  • atLeast(int n) :  적어도 n 번 수행했는지 검증
  • times(int n) :  무조건 n번 수행했는지 검증 (n보다 크거나 작으면 오류로 간주)
  • atMost(int n) : 최대한 n 번 수행했는지 검증
  • never() : 수행되지 않았는지 검증(수행했으면 오류로 간주)
  • timeout(long millisecond ) : 주어진 시간에 초과하였는지 검증(초과하였으면 오류로 간주)

 

@Test
    fun `verifying exact_number of invocations, at least ,never, time`() {
        val mockedList = mock<MutableList<String>>()

        mockedList.add("once")

        mockedList.add("twice")
        mockedList.add("twice")

        mockedList.add("three times")
        mockedList.add("three times")
        mockedList.add("three times")

        //아래의 두 검증 방법은 동일하다
        verify(mockedList).add("once")
        verify(mockedList, times(1)).add("once")

        //지정된 회수만큼 호출되었는지 검증
        verify(mockedList, times(2)).add("twice")
        verify(mockedList, times(3)).add("three times")

        //never()를 이용한 검증. never() == times(0)
        verify(mockedList, never()).add("never happaned")

        mockedList.add("five times")
        mockedList.add("five times")

        mockedList.add("three times")
        mockedList.add("three times")

        /**error
         *  mockList.add("three times")
         *  */

        verify(mockedList, atLeastOnce()).add("three times")
        verify(mockedList, atLeast(2)).add("five times")
        verify(mockedList, atMost(5)).add("three times")

        //시간,횟수 검
        verify(mockedList, timeout(100).times(5)).add("three times")
    }

 

 

 

5. void method의  exception stubbing

void를 리턴 형식으로 갖는 메서드는 stub 하는 법이 약간 다릅니다.

위에서 설명한 일반 stubbing은 whenever(mock.method()). thenReturn(value)(mock.method()). thenReturn(value)형식인데,

mock.method()void값을 가지면 whenever(void)처럼 되기 때문에  문법에 맞지 않기 때문입니다.

 

void(kotlin에서는 Unit)을 그냥 stub 하게 되면 아래와 같은 에러 문구를 볼 수 있을 겁니다.

void method exception stubbing in kotlin

 

그래서 대신 

대신 doThrow(new Exception()). whenever(mock). method()처럼

    @Test(expected = RuntimeException::class)
    fun `void method exception stubbing`() {
        val mockedList = mock<MutableList<String>>()

        doThrow(RuntimeException()).whenever(mockedList).clear()

        mockedList.clear()
    }

혹은 아래와 같이 doNothing으로 stub 하여 하용하는 방법도 존재합니다.

  @Test
    fun `void method exception stubbing in kotlin`() {
        val mockedList = mock<MutableList<String>>()

        doNothing().whenever(mockedList).clear()

        mockedList.clear()

        verify(mockedList, times(1)).clear()
    }

 

 

 

 

6.  순서 검증하기

Mockito- kotlin에서는

inOrder lambda block을 이용하여 순서를  검증할 수 있습니다.

inline fun inOrder(
    vararg mocks: Any,
    evaluation: InOrder.() -> Unit
) {
    Mockito.inOrder(*mocks).evaluation()
}

인라인 함수 inOrder를 호출하여 람다 안에 검증한고 싶은 순서대로  검증할 내용 verify()를 입력합니다

 

mocks는 vararg (가변 인자)로 선언되어있어 여러 개 mock객체를 인자로 받을 수 있습니다.

  @Test
    fun `verification in order`() {
        val singleMock =
            mock<MutableList<String>>()
                .apply {
                    add("was added first")
                    add("was added second")
                }


        inOrder(singleMock) {
            verify(singleMock).add("was added first")
            verify(singleMock).add("was added second")
        }


        val firstMock = mock<MutableList<String>>()
        val secondMock = mock<MutableList<String>>()

        firstMock.add("was called first")
        secondMock.add("was called second")

        //A + B 두개의 mock을  mix 가능
        inOrder(firstMock, secondMock) {
            verify(firstMock).add("was called first")
            verify(secondMock).add("was called second")
        }
    }

 

 

 

 

7. 아무 일도 일어나지 않은(어떤 상호작용도 없었던) mock에 대한 검증

 

verifyZeroInteractions함수를 사용하여 여러 개의  mock객체들이  상호작용이 있었는지 없었는지를 검증합니다.

fun verifyZeroInteractions(vararg mocks: Any) {
    Mockito.verifyZeroInteractions(*mocks)
}
 @Test
    fun `making sure interactions never happened on mock`() {
        val mockOne = mock<MutableList<String>>()
        val mockTwo = mock<MutableList<String>>()
        val mockThree = mock<MutableList<String>>()

        mockOne.add("one")

        verify(mockOne).add("one")
        verify(mockOne, never()).add("two")

        //나머지 2개의 mock은 아무 일이 발생하지 않았음(no interactions). 그에대한 검증
        verifyZeroInteractions(mockTwo, mockThree)
    }

 

 

 

8. 불필요하게 실행되는 코드 찾기

verifyNoMoreInteractions() 함수를 사용하여 더 이상 호출이 있는지 없는지를 검증합니다.

fun <T> verifyNoMoreInteractions(vararg mocks: T) {
    Mockito.verifyNoMoreInteractions(*mocks)
}
 @Test(expected = NoInteractionsWanted::class)
    fun `finding redundant invocations`() {
        val mockedList = mock<MutableList<String>>()

        mockedList.add("one")
        mockedList.add("two")

        verify(mockedList).add("one")

        //아래 구문은 실패한다.
        verifyNoMoreInteractions(mockedList)
    }

위의 예를 보면

mocekdList에 "one", "two"를 add 합니다.

verify(mockedList). add("one")으로 add("one")이 호출되었는지 검증하고

그다음 verifyNomoreInteractions()를 호출하여 더 이상의 상호작용이 있었는지 체크합니다

위의 예에서는 add("two")라는 상호작용이 있었으므로 verifyNomoreInteractions()는 실패합니다.

 

 

 

9. 간단하게 mock 생성하기 - @Mock 어노테이션

1.8.3 버전부터 종종 유용하게 사용할 수 있는 annotation이 추가되었습니다.

  • @Captor는 ArgumentCaptor 생성을 간략화시켰습니다. – 잡아야 하는 파라미터가 generic 클래스이고, 컴파일러 에러를 피하고 싶을 때 유용
  • @Spy - spy(Object) 대신에 사용할 수 있습니다.
  • @InjectMocks - 테스트될 객체에 mock을 자동으로 넣어줍니다.
    • @Mock,@Spy 이 붙은 목객체를 자신의 멤버 클래스와 일치하면 주입시킨다. 
    • 쉽게 말해 실제 테스트할 클래스가 @injectMocks어노테이션을 사용해 목객체를 생성한다.

 

 annotation들은 오직 MockitoAnnotations.initMocks(Object)으로 초기화해야  사용 가능합니다.

 

 

Anotaion의 장점

  • 반복적인 mock 생성 코드를 줄여줍니다.
  • 테스트 클래스의 가독성을 높여줍니다.
  • 필드 이름으로 각각의 mock을 구분하기 때문에, 검증 시에 발생하는 에러를 좀 더 읽기 쉽게 만들어줍니다
class MockitoAnotaionSample {

    @Captor
    lateinit var captor: ArgumentCaptor<Foo>

    @Spy
    val spyOnFoo = Foo("argument")

    @Spy
    lateinit var spyOnBar: Bar

    @InjectMocks
    lateinit var manager: ArticleManager


    @Before
    fun init() {
        MockitoAnnotations.initMocks(this)
    }
}

 

중요!  아래 내용을 반드시 작성해주어야 동작합니다

MockitoAnnotations.initMocks(testClass);

내장 runner인 MockitoJUnitRunner를 이용하셔도 됩니다.

MockitoAnnotations에 대해 더 많은 정보를 읽고 싶으면 아래를 읽어보시길 바랍니다.

https://static.javadoc.io/org.mockito/mockito-core/3.1.0/org/mockito/junit/MockitoJUnitRunner.html

 

MockitoJUnitRunner (Mockito 3.1.0 API)

Mockito JUnit Runner keeps tests clean and improves debugging experience. Make sure to try out MockitoJUnitRunner.StrictStubs which automatically detects stubbing argument mismatches and is planned to be the default in Mockito v3. Runner is compatible with

static.javadoc.io

참고 - https://medium.com/@hanru.yeh/mockito-annotations-with-kotlin-82a3619496f2

 

Unit Test: Mockito Annotations with Kotlin

Our team converted all unit tests from Java to Kotlin. During these practices, we learned more and became familiar with Kotlin and Mockito.

medium.com

 

 

 

10. 연속적인  stubbing 하기

stubbing을 할 때 해당 내용이 호출이 여러 번 되는 상황에서 

1번째 호출과, 2번째 호출 내용, 3번째 호출 내용...... , N번째 호출 내용을 모두 다르게 설정할 수 있습니다.

    @Test(expected = RuntimeException::class)
    fun `stubbing consecutive calls`() {
        val mock = mock<TestClass>()

        whenever(mock.someMethod("some arg"))
            .thenThrow(RuntimeException())  //first return
            .thenReturn("foo")       //second return


        //first call occurred error
        mock.someMethod("some arg")

        //second call print foo
        Assert.assertEquals("foo", mock.someMethod("some arg"))

        //All subsequent calls print foo
        Assert.assertEquals("foo", mock.someMethod("some arg"))
    }

위의 코드를 보면 someMethod() 첫 번째 호출에는 "some arg"를 

두 번째   someMethod() 호출에는 RuntimeException을

세 번째  someMethod() 호출에는 "foo"를 반환합니다.

 

 

 

 

11. callback을 stubbing 하기

이때까지의 예제에서는 stub 할 때 모두 특정값을 넣었습니다.

만약 mock의 상태나 메서드 인자 값에 따라 다른 값을 돌려주게 하게 만들고 싶다면 어떻게 해야 할까요?

 Answer <?> 클래스를 사용하면 가능합니다.

하지만 아주 특별한 상황이 아니라면 크게 사용할 일은 없을 듯합니다.

@Test
    fun `stubbing with callbacks`() {
        val mock = mock<TestClass> {
            on {
                mock.someMethod(ArgumentMatchers.anyString())
            } doAnswer {
                if (it.arguments[0] == "foo")
                    "foo"
                else
                    "none"
            }
        }

        println(mock.someMethod("foo"))
        println(mock.someMethod("ss"))

        verify(mock).someMethod("foo")
        verify(mock).someMethod("ss")
    }

위 예제는 doAnser 블록 안에서 argument값을 확인하고  

argument값에 따라 반환 내용을 다르게 합니다.

 

 

 

12. void method를 stubbing 하기 위한 doThrow || doAnswer || doNothing || doReturn 

 

 

13. 실제 객체 감시하기

Mockito에서는 real 객체에 대한 스파이를 생성할 수 있습니다.

만약 spy(스파이)를 호출하게 되면 실제 method가 호출됩니다.( method가 stub 되지 않았을 경우)

 

real객체를 감시하는 것은 "Partial mocking"이라는 개념과 관련되어 있습니다.

partial mocking이란  클래스의  일부 method는 mocking 하고 그  나머지  method는  mocking 하고 싶을 때 

즉, 일부만 mocking 하고자 할 때 사용합니다. 

아래의 예로 사용방법을 보도록 하겠습니다.

  @Test
    fun `spying on real object`() {
        val list = LinkedList<String>()
        val spy = spy(list)

        //특정 메소드만 stub하는것이 가능하다
        whenever(spy.size).thenReturn(100)


        //stub되지 않았기때문에 real method를  실행한다.
        spy.add("one")
        spy.add("two")


        println(spy[0])

        //stub된 size 100을 출력
        println(spy.size)

        verify(spy).add("one")
        verify(spy).add("two")
        verify(spy)[0]
        verify(spy).size
    }
    @Test
    fun `caution use spy`() {
        val list = LinkedList<String>()
        val spy = spy(list)

        //실제 객체에 아무것도 없기 때문에 whenever호출시 IndexOutOfBoundsExcepsion이 발생
        //whenever(spy[0]).thenReturn("foo")

        //그렇기 때문에 doReturn으로  stubbing
        doReturn("foo").whenever(spy)[0]

        println(spy[0])

        verify(spy)[0]
    }

스파이(real object를 감시하기)를 할 때 알아야 할 중요한 점은

 

1. 가끔 stubbing 된 스파이에 대해 whenever(object)를 사용할 수 없습니다. (doReturn 등을  사용해야 합니다.)

2. final method는 조심해야 합니다. Mockito는 final method를 mock으로 만들지 않기 때문에 스파이(real object를 감시)하면서  final method를  stub 하게 되면 문제가 발생합니다. 실제 객체가 아닌 spy에 넘겨준 mock의 method가 호출됩니다.  mock 객체는 필드를 초기화하지 않았기 때문에 일반적으로 NPE 가 발생합니다.

 

 

 

 

14.  stubbing 되지 않은 method에   default값  설정하기

val mock = mock<TestSample>(defaultAnswer = Mockito.RETURNS_SMART_NULLS)
val mockTwo = mock<TestSample>(defaultAnswer = YourOwnAnswer())

 mock  객체를 만들면서 생성자로 여러 인자를 넣어줄 수 있는데

그중에 default(기본적인 리턴 값)을 stub 되지 않은 메서드가 호출될 때 사용할 수 있습니다.

 

 

 

 

15. 파라미터 검증하기

arugmentCaptor클래스를 시용하여 파라미터로 들어오는 값들을 캡처하고 

그 값들을 검증할 수 있습니다.

    @Test
    fun `capturing arguments for further assertions`() {
        val myClass = mock<TestClass>()

        myClass.someMethod("1", "2")
        myClass.someMethod("3", "4")

        argumentCaptor<String>().apply {
            verify(myClass, times(2)).someMethod(capture())

            Assert.assertEquals(4, allValues.size)
            Assert.assertEquals("1", firstValue)
        }
    }

주의할 점은 ArgumentCaptor를 검증용으로만 사용해야 하고 stubbing용으로 사용하면 안 된다는 점입니다.

ArgumentCaptor는 블록 바깥쪽에서 만들어지기 때문에 stubbing 할 때 ArgumentCaptor를 사용하면 테스트 가독성이 떨어지게 됩니다.

또한 , stubbing 된 메서드가  호출되지 않으면 아무 파라미터도 잡히지 않기 때문에 결함의 범위가 넓어집니다.

 

 

 

 

16.  Real partial mock

(13번)에서  본 real Object 감시하기에서 본 내용의 연장선입니다.

spy을 이용하여 partial  mock을 생성할 수 있습니다.

  @Test
    fun `real partial mocks`() {
        // spy() method를 이용해 partial mock을 생성할 수 있다.
        val list = spy(LinkedList<String>())

        // mock에 대해 선택적으로 partial mock 기능이 동작하게 만들 수 있다.
        val mock = mock<TestClass>()
        // 실제 구현이 안전하다는 것을 확신할 수 있다.
        // 만일 실제 구현이 예외를 던지거나 객체의 특정 상태에 의존하고 있다면 문제가 생길 것이다.
        whenever(mock.someMethod()).thenCallRealMethod()
    }

 

 

 

17.  mock 다시 설정하기

보통은 mock을 리셋해서 사용하지 않고 각각의 테스트를 위해 새로운 mock을 생성합니다.

reset()을 사용하기보다는 지나치게 길거나 지나치게 자세한 테스트를 고쳐서 간결하고 한 가지만 테스트하는 테스트로 바꾸시길 바랍니다. code smell일 가능성이 제일 높은 경우는 테스트 method 중간에서 reset()을 사용한 경우입니다. 

 

웬만하면 reset 사용은 지양하고 , 꼭 필요한 경우에만 reset()을 사용하도록 합시다.

 @Test
    fun `resetting mocks`() {
        val mock = mock<MutableList<String>>()

        whenever(mock.size).thenReturn(10)

        Assert.assertEquals(10, mock.size)

        reset(mock)

        Assert.assertEquals(0, mock.size)
    }

 

 

 

18. Aliases for behavior driven development 

 

Behavior Driven Development 스타일의 테스트 작성방법은

테스트 method에 기본으로 //given //when //then이라고 주석을 달아두는 것입니다.

이렇게 함으로써 우리가 어떻게 테스트를 작성해야 하고, 여러분이 이렇게 만들도록 장려할 수 있습니다.

 

BDD 알아보기

 

BDD 알아보기

BDD 알아보기 BDD는 TDD둘다 소프트웨어 개발 방법입니다. TDD는 Test Driven Development로 테스트 주도 개발이라 합니다. 테스트를 먼저 작성하고, 그 뒤에 테스트케이스를 통과하는 코드를 작성하는 방식으로..

beomseok95.tistory.com

여기서 문제는 mockito에서  when을 이용한 구문들이 있기 때문에 

 bdd의 //given //when //then주석에 맞아떨어지지 않기 때문입니다.

왜냐하면 stubbing이 when이 아닌  given에 속하기 때문입니다.

Mockito는 그래서 BDD스타일의 테스트를 작성할 수 있도록 아래와 같은 메서드를 지원합니다.

   @Test
    fun `aliases for behavior driven development`() {
        val calculatorService = mock<CalculatorService>()

        //given
        given(calculatorService.add(20.0, 10.0)).willReturn(30.0)

        //when
        val result = calculatorService.add(20.0, 10.0)

        //then
        Assert.assertThat(30.0, CoreMatchers.`is`(result))
    }

 

verify 대신 `then`키워드를 사용하여  BDD 스타일로 검증할 수도 있습니다. 

 given(dog.bark()).willReturn(2);

 // when
 ...

 then(person).should(times(2)).ride(bike);

 

 

 

 

19. Mocking Details

MockingDetails클래스를 사용하여 Mock 된 객체의 정보를 알 수 있습니다.

  • isMock()  : 인자로 받은 객체가 Mock객체인지 리턴합니다.
  • isSpy() : 인자로 받은 객체가 Spy로 생성된 객체인지 확인하여 리턴합니다.
  • typeToMock : Mock객체의   ClassType을 리턴합니다.
  • defaultAnswer: 기본으로 설정되어있는 defaultAnswer을 리턴합니다.
  • invocations :  mock객체에 일어났던 상호작용들을 List로  반환합니다.
  • stubbing : mock객체에  Stubbing 된 내용들을 List로 반환합니다.
   @Test
    fun `mocks detail`() {
        val mockedList = mock<List<String>> {
            on { get(0) } doReturn "hello"
        }

        println("isMock : " + Mockito.mockingDetails(mockedList).isMock)
        println("isSpy : " + Mockito.mockingDetails(mockedList).isSpy)

        mockedList[0]

        with(mockingDetails(mockedList)) {
            println("typeToMock : ${mockCreationSettings.typeToMock}")
            println("defaultAnser : ${mockCreationSettings.defaultAnswer}")
            println("invocations : $invocations")
            println("stubbings : $stubbings")
        }
    }

 

//result

isMock : true
isSpy : false
typeToMock : interface java.util.List
defaultAnser : RETURNS_DEFAULTS
invocations : [list.get(0);]
stubbings : [list.get(0); stubbed with: [Returns: hello]]

 

MockingDetails 알아보기