【问题标题】:Why is a $MockitoMock$ instance not being identified as a mock?为什么 $MockitoMock$ 实例没有被识别为模拟?
【发布时间】:2018-01-08 16:46:34
【问题描述】:

我正在使用 Kotlin、Mockito 和 MockitoJRunner 运行以下简化测试:

open class SomeClassToBeMocked @Inject constructor() {
    fun map(foo: Foo): Bar {...}
}

@Mock
private lateinit var someMock: SomeClassToBeMocked
@InjectMocks
private lateinit var subject: Subject

@Test
fun shouldAssertSomething() {
    val foo = Foo() // from Foo.kt
    val bar = Bar() // from Bar.java from *another module*
    whenever(someMock.map(foo)).thenReturn(bar) // breakpoint[1]

    subject.myMethod(foo)

    verify(someMock).map(foo)
}

此模式适用于代码的其他部分,但不适用于此特定测试,我收到以下错误消息:

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.
   Mocking methods declared on non-public parent classes is not supported.
2. inside when() you don't call method on mock but on some other object.

当我在breakpoint[1] 调试代码时,我可以看到 someMock 是类SomeClassToBeMocked$MockitoMock$ 的一个实例。此外,如果我尝试在breakpoint[1] 之前立即调用someMock.map(foo),它确实会运行原始方法,而不是像所有模拟一样返回null

对这里可能发生的事情有什么想法吗?

UPDATE-1:我已经检查了错误消息中选项 1 的所有可能性。我也试过mock(SomeClassToBeMocked::class.java) 并得到同样的错误信息。这在一些最简单的类中总是会发生,只有一个公共方法只将对象 A 转换为对象 B。

UPDATE-2:如果有什么不同的话,我只是注意到在发生这种情况的情况下,Bar() 与测试位于不同的模块中。我已经更新了代码以反映这一点。

UPDATE-3:如果我创建一个名为SomeClassToBeMocked 的接口并将原始类重命名为SomeClassToBeMockedImpl,那么一切都会像魅力一样工作。但是,我仍然想弄清楚为什么会发生这种情况以及如何避免为此创建接口。

【问题讨论】:

  • 显式创建 someMock = mock(SomeClassToBeMocked.class); 是否有效?
  • 您是否检查了错误消息第 1 条中列出的所有可能性?也就是说,该方法可以是最终的、私有的还是在非公共父类中声明?
  • @DawoodibnKareem 是的,所有可能性都已检查。这个类看起来和我在这里发布的完全一样:类和方法的签名相同。
  • @MaciejKowalski 它没有:我得到完全相同的错误

标签: java unit-testing kotlin mockito


【解决方案1】:

为了使用 Mockito 模拟函数的返回值,您需要使用 open 关键字对其进行标记:

open class SomeClassToBeMocked @Inject constructor() {
    open fun map(foo: Foo): Bar {...}
}

问题是 Mockito 不能模拟最终(不能被覆盖)函数。与 Java 不同,Kotlin 需要对可覆盖的成员进行显式注释。

【讨论】:

  • 如果您查看我的问题中的代码示例,您可以看到我试图模拟的类已经打开。还有其他想法吗?
  • 您必须使用open 修饰符标记SomeClassToBeMocked 类和map 函数。我的回答是关于开启功能,请再仔细检查一遍。
  • @andersonvom 你能用我的回答解决这个问题吗?
猜你喜欢
  • 1970-01-01
  • 2021-02-22
  • 2022-07-11
  • 2019-12-31
  • 2023-03-28
  • 1970-01-01
  • 2011-06-07
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多