ArgumentMatchers.any 不能为空

Ana*_*dze 27 android unit-testing mockito viewmodel kotlin

我正在尝试测试ViewModel以确保 livedata 正确更新。但是,当使用ArgumentMatchers.any()它失败时IllegalStateException说:

ArgumentMatchers.any(mViewModel.CountSubscriber::class.java) 不能为空

@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)
}
Run Code Online (Sandbox Code Playgroud)

我正在使用 Kotlin 并具有以下依赖项:

testImplementation 'junit:junit:4.12'
testImplementation "org.mockito:mockito-inline:2.23.4"
testImplementation "com.nhaarman.mockitokotlin2:mockito-kotlin:2.1.0"
Run Code Online (Sandbox Code Playgroud)

这是我的进口:

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
Run Code Online (Sandbox Code Playgroud)

奇怪的是它以前可以工作,我不知道发生了什么可能会影响它。

Nab*_*bzi 30

让匹配器与 Kotlin 一起工作可能是一个问题。如果您有一个用 kotlin 编写的方法不接受可空参数,那么我们无法使用 Mockito.any() 匹配它。这是因为它可以返回 void 并且这不能分配给不可为空的参数。

如果匹配的方法是用 Java 编写的,那么我认为它会起作用,因为所有 Java 对象都是隐式可为空的。

一种可能的解决方案是使用像mockito-kotlin这样的库, 但是您可以自己用几行代码轻松解决这个问题。

如果你需要输入任何(类型:类)

private fun <T> any(type: Class<T>): T = Mockito.any<T>(type)
Run Code Online (Sandbox Code Playgroud)

或者

您可以使用此匹配器代替 Matchers.any() :

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

并在您的 kotlin 测试中使用MockitoHelper.anyObject()而不是any()

您可以在这篇文章中找到更多信息:在 Kotlin 中使用 Mockito

在这篇文章中有一个关于可能的解决方案的讨论: Is it possible to use Mockito in Kotlin?

  • 这是错误的答案。正确的答案是你只需要使用“import kotlin.any”而不是“import mockito.any”即可。 (3认同)

Hao*_*min 22

@Ana Koridze 在问题的评论部分提到了正确的解决方案。是的,如果您使用的是 Koltin + mockitoKotlin。确保您正在使用以下导入:

1 - 使用 Mockito-kotlin:

import org.mockito.kotlin.any 来自 Mockito-kotlin 而不是 import org.mockito.Mockito.any

testImplementation "org.mockito.kotlin:mockito-kotlin:$mockito_kotlin_version"
Run Code Online (Sandbox Code Playgroud)

2 - 或者如果您使用的是 nhaarman 在插入之前创建的旧版 mockito kotlin 版本

import com.nhaarman.mockitokotlin2.any 来自 nhaaram 的 Mockito-kotlin 而不是 import org.mockito.Mockito.any

testImplementation "com.nhaarman.mockitokotlin2:mockito-kotlin:$mockito_kotlin2_version"
Run Code Online (Sandbox Code Playgroud)

顺便说一句,如果您使用的是 Android Studio 或 IntelliJ IDEA。在any()从mockitokotlin库应该是italic默认样式/颜色方案。


注意any()行尾。这是来自mockitokotlin

在此处输入图片说明

这是any()来自mockito

在此处输入图片说明

感谢@Sattar 推荐的编辑。

  • 我遇到了同样的问题,然后阅读了您的答案并检查了我的导入,现在它可以工作了!谢谢! (3认同)
  • 唯一对我有用的东西。谢谢@浩民 (2认同)

小智 13

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

        `when`(myMock.doesThis(any(), anyOrNull())).thenReturn(someObject)
Run Code Online (Sandbox Code Playgroud)


Sat*_*tar 6

使用Mockito-kotlin

testImplementation "org.mockito.kotlin:mockito-kotlin:$mockito_kotlin_version"
Run Code Online (Sandbox Code Playgroud)

这将使用任何适用于 kotlin 的库,因为这是 Mockito 的包装库,但适用于 kotlin