kotlin and ArgumentCaptor - IllegalStateException

后端 未结 8 1286
长发绾君心
长发绾君心 2020-12-30 18:44

I have a problem with capturing the Class argument via ArgumentCaptor. My test class looks like this:

@RunWith(RobolectricGradleTestRunner::class)
@Config(sd         


        
相关标签:
8条回答
  • 2020-12-30 18:54

    The return value of classCaptor.capture() is null, but the signature of IActivityHandler#navigateTo(Class, Boolean) does not allow a null argument.

    The mockito-kotlin library provides supporting functions to solve this problem.

    Code should be:

        @Captor
        lateinit var classCaptor: ArgumentCaptor<Class<BaseActivity>>
    
        @Captor
        lateinit var booleanCaptor: ArgumentCaptor<Boolean>
    
        ...
    
        @Test
        fun thatNavigatesToAddListScreenOnAddClicked(){
            //given
    
            //when
            objectUnderTest?.addNewList()
    
            //then
            verify(activityHandlerMock).navigateTo(
    com.nhaarman.mockitokotlin2.capture<Class<BaseActivity>>(classCaptor.capture()), 
    com.nhaarman.mockitokotlin2.capture<Boolean>(booleanCaptor.capture())
    )
            var clazzValue = classCaptor.value
            assertNotNull(clazzValue);
            val booleanValue = booleanCaptor.value
            assertFalse(booleanValue);
        }
    

    OR

    var classCaptor = com.nhaarman.mockitokotlin2.argumentCaptor<Class<BaseActivity>>()
    var booleanCaptor = com.nhaarman.mockitokotlin2.argumentCaptor<Boolean>()
    ...
     verify(activityHandlerMock).navigateTo(
    classCaptor.capture(), 
    booleanCaptor.capture()
    )
    

    also in build.gradle add this:

    testImplementation "com.nhaarman.mockitokotlin2:mockito-kotlin:2.2.0"
    
    0 讨论(0)
  • 2020-12-30 18:57

    You can write a wrapper over argument captor

    class CaptorWrapper<T:Any>(private val captor:ArgumentCaptor<T>, private val obj:T){
        fun capture():T{
            captor.capture()
            return obj
        }
    
        fun captor():ArgumentCaptor<T>{
            return captor
        }
    }
    
    0 讨论(0)
  • 2020-12-30 19:02

    Another approach:

    /**
     * Use instead of ArgumentMatcher.argThat(matcher: ArgumentMatcher<T>)
     */
    fun <T> safeArgThat(matcher: ArgumentMatcher<T>): T {
        ThreadSafeMockingProgress.mockingProgress().argumentMatcherStorage
            .reportMatcher(matcher)
        return uninitialized()
    }
    
    @Suppress("UNCHECKED_CAST")
    private fun <T> uninitialized(): T = null as T
    

    Usage:

    verify(spiedElement, times(1)).method(
        safeArgThat(
            CustomMatcher()
        )
    )
    
    0 讨论(0)
  • 2020-12-30 19:05

    For some, there is a file, MockitoKotlinHelpers.kt provided by Google in the Android Architecture repo. It provides a convenient way to call capture.. just call verify(activityHandlerMock).navigateTo(capture(classCaptor), capture(booleanCaptor))

    Update: If the above solution does not work for you, please check Roberto Leinardi's solution in the comments below.

    0 讨论(0)
  • 2020-12-30 19:07

    As stated by CoolMind in the comment, you first need to add gradle import for Kotlin-Mockito and then shift all your imports to use this library. Your imports will now look like:

    import com.nhaarman.mockitokotlin2.argumentCaptor
    import com.nhaarman.mockitokotlin2.any
    import com.nhaarman.mockitokotlin2.eq
    import com.nhaarman.mockitokotlin2.isNull
    import com.nhaarman.mockitokotlin2.mock
    import com.nhaarman.mockitokotlin2.verify
    

    Then your test class will be something like this:

    val mArgumentCaptor = argumentCaptor<SignUpInteractor.Callback>()
    
    @Test
    fun signUp_success() {
        val customer = Customer().apply {
            name = "Test Name"
            email = "test@example.com"
            phone = "0123444456789"
            phoneDdi = "+92"
            phoneNumber = ""
            countryCode = "92"
            password = "123456"
        }
        mPresenter.signUp(customer)
        verify(mView).showProgress()
        verify(mInteractor).createAccount(any(), isNull(), mArgumentCaptor.capture())
    }
    
    0 讨论(0)
  • 2020-12-30 19:08

    Use kotlin-mockito https://mvnrepository.com/artifact/com.nhaarman/mockito-kotlin/1.5.0 as dependency and sample code as written below :

    argumentCaptor<Hotel>().apply {
        verify(hotelSaveService).save(capture())
    
        assertThat(allValues.size).isEqualTo(1)
        assertThat(firstValue.name).isEqualTo("İstanbul Hotel")
        assertThat(firstValue.totalRoomCount).isEqualTo(10000L)
        assertThat(firstValue.freeRoomCount).isEqualTo(5000L)
    }
    
    0 讨论(0)
提交回复
热议问题