使用Kotlin和Mockito在测试中无法模拟最终类

28

我正在尝试运行一个简单的仪器测试:

class DefaultTest {

    private val networkHelper = Mockito.mock(NetworkHelperImpl::class.java)

    @Test fun inter() {
        given(networkHelper.isConnectedToNetwork()).willReturn(true)
        assertFalse { networkHelper.isConnectedToNetwork(false) }
    }
}

但是我因为错误无法做到:

Mockito cannot mock/spy because :
- final class

我该如何避免它?

正如这个指南所说:

https://antonioleiva.com/mockito-2-kotlin/

我创建了一个文件:

enter image description here

使用这行代码:

mock-maker-inline

但没有任何变化。

Gradle很糟糕(我正在学习),但必须工作。我也使用单元测试,现在我有:

//Tests
testImplementation 'junit:junit:4.13-beta-3'

testImplementation 'org.jetbrains.kotlin:kotlin-stdlib:1.3.41'
testImplementation 'org.jetbrains.kotlin:kotlin-test-junit:1.3.41'

androidTestImplementation 'org.mockito:mockito-core:3.0.0'
androidTestImplementation 'org.mockito:mockito-android:2.24.5'
androidTestImplementation "com.nhaarman.mockitokotlin2:mockito-kotlin:2.1.0"

testImplementation 'org.amshove.kluent:kluent:1.14'

androidTestImplementation 'androidx.test:runner:1.2.0'
androidTestImplementation 'androidx.test:core:1.2.0'
androidTestImplementation 'androidx.test.ext:junit:1.1.1'
androidTestImplementation 'androidx.test:rules:1.2.0'

1
我知道这不是一个答案 - 但是对于Kotlin的模拟,我转向了https://mockk.io/,并且从此没有回头。您可以模拟最终类,并且如果您遇到任何异步挂起函数,它还带有内置工具。内置于Kotlin中,专为Kotlin而设计。 - Laurence
6个回答

46

只需简单添加

testImplementation("org.mockito:mockito-inline:2.8.47")

解决了问题。


8
  1. 按照以下步骤操作:https://antonioleiva.com/mockito-2-kotlin/
  2. 更新库,并将androidTestImplementation替换为testImplementation。例如:

    testImplementation "com.nhaarman.mockitokotlin2:mockito-kotlin:2.1.0 (更新)

    testImplementation 'org.mockito:mockito-core:3.0.0' (更新)

    testImplementation 'org.mockito:mockito-android:2.24.5' (将androidTestImplementation替换为testImplementation)

  3. 从每个测试类中删除MockitoAnnotations.initMocks(this)

已在Android Studio 3.5上测试通过


这在我身上发生了一段时间,但对我而言,我没有 mockito-core 依赖。 - mochadwi
1
似乎只能在本地测试中使用(testImplementation),我使用了@Cristi Constantin的依赖项,只在本地测试中起作用。 - Campino

2

这是因为在Kotlin中类默认是final的,所以Mockito无法从final类创建模拟。

您可以将类标记为open,以及您想要测试的每个方法。

例如

open class AbcClass {
    open fun foo() = print("foo")
    fun bar() = print("bar")
}

AbcClass类是可模拟的,它的foo()方法可以通过Mockito进行测试。

我曾经遇到过类似的问题,这是我解决问题的方法。


1
你尝试过使用 mockito-kotlin 吗?将其添加到你的依赖中即可:
testImplementation "com.nhaarman.mockitokotlin2:mockito-kotlin:2.1.0"


5
我添加了,但是没有任何变化。 - KirstenLy
同样的问题,你能分享一下应用程序中包含的所有依赖项吗? - Sathish Gadde

0
我认为这里的问题在于你只为仪器测试编译了Mockito - 即在androidTest中的测试。然而,根据你放置Mockito扩展配置的位置,你想要在单元测试中执行此操作。
当你使用androidTestImplementation时,你正在为仪器测试编译该依赖项。使用testImplementation将为单元测试编译。请替换:
androidTestImplementation 'org.mockito:mockito-core:3.0.0'
androidTestImplementation 'org.mockito:mockito-android:2.24.5'
androidTestImplementation "com.nhaarman.mockitokotlin2:mockito-kotlin:2.1.0"

使用:

testImplementation 'org.mockito:mockito-core:3.0.0'
testImplementation 'org.mockito:mockito-android:2.24.5'
testImplementation "com.nhaarman.mockitokotlin2:mockito-kotlin:2.1.0"

-1

在你的测试类上加上注解@RunWith(MockitoJUnitRunner::class)。这样你的类会变成这个样子:

@RunWith(MockitoJUnitRunner::class)
class DefaultTest {

    private val networkHelper = Mockito.mock(NetworkHelperImpl::class.java)

    @Test fun inter() {
        given(networkHelper.isConnectedToNetwork()).willReturn(true)
        assertFalse { networkHelper.isConnectedToNetwork(false) }
    }
}

对我来说,我做了和你一样的事情,但失败了。我只是错过了那个注释部分。添加注释后,它按预期工作。


但是这里的对象是间谍或模拟对象。我们需要在哪里定义它? - Sathish Gadde

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接