我开始学习Kotlin和Mockito,所以我编写了一个简单的模块来测试它。
AccountData_K.kt:
open class AccountData_K {
var isLogin: Boolean = false
var userName: String? = null
fun changeLogin() : Boolean {
return !isLogin
}
}
AccountDataMockTest_K.kt:
class AccountDataMockTest_K {
@Mock
val accountData = AccountData_K()
@Before
fun setupAccountData() {
MockitoAnnotations.initMocks(this)
}
@Test
fun testNotNull() {
assertNotNull(accountData)
}
@Test
fun testIsLogin() {
val result = accountData.changeLogin()
assertEquals(result, true)
}
@Test
fun testChangeLogin() {
`when`(accountData.changeLogin()).thenReturn(false)
val result = accountData.changeLogin()
assertEquals(result, false)
}
}
当我运行测试时,它会报告有关testChangeLogin()
方法的异常:
org.mockito.exceptions.misusing.MissingMethodInvocationException:
when() requires an argument which has to be 'a method call on a mock'.
For example:
when(mock.getArticles()).thenReturn(articles);
Also, this error might show up because:
1. you stub either of: final/private/equals()/hashCode() methods.
Those methods *cannot* be stubbed/verified.
2. inside when() you don't call method on mock but on some other object.
3. the parent of the mocked class is not public.
It is a limitation of the mock engine.
at com.seal.materialdesignwithkotlin.AccountDataMockTest_K.testChangeLogin(AccountDataMockTest_K.kt:57)
...
我怀疑为什么这个方法不是模拟方法调用...
所以请帮助我,谢谢。
答案 0 :(得分:9)
默认情况下Kotlin的classes and members are final。 Mockito无法mock final classes nor methods。要使用Mockito,您需要open
您想要模拟的方法:
open fun changeLogin() : Boolean {
return !isLogin
}
进一步阅读
PS。在我看来,只要你通过ie ISP保持接口很小,使用Mockito或其他模拟框架的测试代码比手写的假货/存根更难以理解和理解。
答案 1 :(得分:4)
正如@miensol所提到的那样,出现问题是因为Kotlin默认情况下类为final
。错误消息不是很清楚,尽管这部分提到final
是可能的原因之一:
- 你存根:final / private / equals()/ hashCode()方法。
醇>
在与Mockito的单元测试中,有一个项目专门用于帮助处理Kotlin“默认最终”。对于JUNIT,您可以使用kotlin-testrunner这是一种简单的方法,可以让任何Kotlin测试自动打开类,以便在类加载器加载时进行测试。用法很简单,只需添加一个@RunWith(KotlinTestRunner::class)
注释,例如:
@RunWith(KotlinTestRunner::class)
class MyKotlinTestclass {
@Test
fun test() {
...
}
}
Never say final: mocking Kotlin classes in unit tests
一文中详细介绍了这一点这允许以自动方式覆盖您的用例,允许所有类被模拟,否则将不被允许。
答案 2 :(得分:0)
对于任何发表这篇文章的人,您可以使用kotlin-allopen库打开您的类进行测试:
首先在您的build.gradle(项目)文件中添加依赖项:
dependencies {
classpath "org.jetbrains.kotlin:kotlin-allopen:$kotlin_version"
}
之后,将该插件应用到您的build.gradle(应用程序Mobdule)文件中:
apply plugin: 'kotlin-allopen'
然后指定将打开类的注释列表:
allOpen {
annotation('com.example.myproject.OpenForTesting')
}
并在项目的名为OpenForTesting的文件中定义注释(文件必须位于项目com.example.myproject.OpenForTesting中):
/**
* This annotation allows us to open some classes for mocking purposes while they are final in
* release builds.
*/
@Target(AnnotationTarget.ANNOTATION_CLASS)
annotation class OpenClass
/**
* Annotate a class with [OpenForTesting] if you want it to be extendable in debug builds.
*/
@OpenClass
@Target(AnnotationTarget.CLASS)
annotation class OpenForTesting
并对要打开的每个类使用此批注
@OpenForTesting
以下是有关全开放的Kotlin官方文档:https://kotlinlang.org/docs/reference/compiler-plugins.html