简体   繁体   中英

ArgumentMatchers.any must not be null

I am trying to test ViewModel to make sure livedata gets updated correctly. However when using ArgumentMatchers.any() it fails with IllegalStateException saying:

ArgumentMatchers.any(mViewModel.CountSubscriber::class.java) must not be null

@Test
fun emitValueIfCountIs7() {
    doAnswer { invocation: InvocationOnMock ->
        val subscriber: mViewModel.CountSubscriber = invocation.getArgument(0)
        subscriber.onNext(7)
        null
    }.`when`(countUseCase).execute(
        ArgumentMatchers.any(mViewModel.CountSubscriber::class.java),
        ArgumentMatchers.any(Parameters::class.java)
    )
    
    // When
    mViewModel.getCount()
    
    // Verify
    assert(mViewModel.countResponse.value != null)
}

I am using Kotlin and have the following dependencies:

testImplementation 'junit:junit:4.12'
testImplementation "org.mockito:mockito-inline:2.23.4"
testImplementation "com.nhaarman.mockitokotlin2:mockito-kotlin:2.1.0"

Here are my imports:

import androidx.arch.core.executor.testing.InstantTaskExecutorRule
import com.nhaarman.mockitokotlin2.doAnswer
import io.reactivex.Observable
import org.junit.Before
import org.junit.Rule
import org.junit.Test
import org.mockito.ArgumentMatchers.any
import org.mockito.Mock
import org.mockito.Mockito
import org.mockito.MockitoAnnotations
import org.mockito.invocation.InvocationOnMock

Strange thing is that it used to work before, and I don't know what has happened that could affect this.

Getting matchers to work with Kotlin can be a problem. If you have a method written in kotlin that does not take a nullable parameter, then we cannot match with it using Mockito.any(). This is because it can return void and this is not assignable to a non-nullable parameter.

If the method being matched is written in Java, then I think that it will work as all Java objects are implicitly nullable.

One possible solution would be to use a library like mockito-kotlin But you can solve this issue easily with a few lines of code yourself.

If you need typed any(type: Class)

private fun <T> any(type: Class<T>): T = Mockito.any<T>(type)

OR

You can use this matcher instead of Matchers.any() :

object MockitoHelper {
fun <T> anyObject(): T {
    Mockito.any<T>()
    return uninitialized()
}
@Suppress("UNCHECKED_CAST")
   fun <T> uninitialized(): T =  null as T
}

and use MockitoHelper.anyObject() instead of any() in your kotlin tests.

You can find more information in this post: Using Mockito with Kotlin

There is a discussion about possible solutions in this post : Is it possible to use Mockito in Kotlin?

The correct solution is mentioned in the comment section of the question by @Ana Koridze. Yes, if you are using Koltin + mockitoKotlin. Make sure you are using the following import:

1 - Using the Mockito-kotlin:

import org.mockito.kotlin.any from Mockito-kotlin instead of import org.mockito.Mockito.any

testImplementation "org.mockito.kotlin:mockito-kotlin:$mockito_kotlin_version"

2 - Or if you are using older mockito kotlin version original created by nhaarman before the intergation

import com.nhaarman.mockitokotlin2.any from nhaaram's Mockito-kotlin instead of import org.mockito.Mockito.any

testImplementation "com.nhaarman.mockitokotlin2:mockito-kotlin:$mockito_kotlin2_version"

BTW, if you are using Android Studio or IntelliJ IDEA. the any() from mockitokotlin library should be italic by default style/color scheme.


Notice the any() at the end of line. This is from mockitokotlin

在此处输入图片说明

And here is the any() from mockito

在此处输入图片说明

Thanks @Sattar for the recommended edit.

use Mockito-kotlin

testImplementation "org.mockito.kotlin:mockito-kotlin:$mockito_kotlin_version"

this will use any that works for kotlin as this is a wrapper lib for Mockito but for kotlin

This is what worked for me,

  1. either replaced all generic any() s , with a specific anyTYPE(), ie anyInt() , anyList() etc from core lib org.mockito:mockito-core and it fixes the (nullability)issue, it seems the specific definitions with type can handle null. this option does not require you to import any extra lib

or

  1. if you really need to use the generic type any() , add this official Mckito extension lib https://github.com/mockito/mockito-kotlin and make sure you use the any() from this lib (by making sure your imports has this in it import org.mockito.kotlin.any )

I suggest to start using MockK lib https://github.com/mockk/mockk instead of Mockito as it is a Mock library for K otlin = MockK)

however, if you feel lazy to switch right now or maybe dealing with legacy tests (as in my case :), this should fix your issue too.

For me all solutions above were not enough - in addition to that I had to mark the called method as an 'open' method. According to this: https://github.com/mockito/mockito-kotlin/wiki/Parameter-specified-as-non-null-is-null The method is final and Mockito couldn't mock it so I had to add 'open'.

mockito-kotlin添加了对anyOrNull()可为空参数的支持

        `when`(myMock.doesThis(any(), anyOrNull())).thenReturn(someObject)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM