一个简单的kotlin类与mockito测试引起MissingMethodInvocationException

我开始学习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()方法的exception:

 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) ... 

我怀疑为什么该方法不是一个模拟方法调用…

所以请帮助我,谢谢。

默认情况下,Kotlin的课程和成员是最终的 。 Mockito不能嘲笑最终课程或方法 。 要使用Mockito,你需要open你想要模拟的方法:

 open fun changeLogin() : Boolean { return !isLogin } 

进一步阅读

  • 在Kotlin中可以使用Mockito吗?
  • 没有开放课程,可以和Kotlin一起使用Mockito吗?

PS。 在我看来,只要你通过ISP保持你的接口小,使用Mockito或其他模拟框架的测试代码很少比手写的假货/存根更易读易懂。

正如@miensol所提到的,你的问题发生是因为类在Kotlin中默认是final的。 错误信息不是很清楚,虽然这部分提到final的可能原因之一:

  1. 你存根:final / private / equals()/ hashCode()方法。

有一个项目专门用来帮助处理Kotlin在Mockito的unit testing中“默认最终”。 对于JUNIT,您可以使用kotlin-testrunner ,这是一种简单的方法,可以让任何Kotlin测试自动打开类,以便在类加载器加载时进行测试。 用法很简单,只需添加@RunWith(KotlinTestRunner::class)一个注释,例如:

 @RunWith(KotlinTestRunner::class) class MyKotlinTestclass { @Test fun test() { ... } } 

这篇文章在文章Never say final里被彻底的讲述了:在unit testing中嘲笑Kotlin类

这将自动覆盖您的用例,允许所有类别被嘲笑,否则将不被允许。