Mockito.mock何时创建部分模拟而不是“完整”模拟?

时间:2019-11-12 20:54:11

标签: java kotlin mockito partial-mocks

给出以下代码:

// Subject.kt

open class Subject(var x: Int) {

    constructor(): this(42) {
        println("made it")
    }

    fun doit() {
        x += 1
        println("did it: $x")
    }
}
// Tests.kt

import org.junit.jupiter.api.Test
import org.mockito.Mockito

class Tests {
    @Test
    fun makeit() {
        val mock = Mockito.mock(Subject::class.java)

        val details = Mockito.mockingDetails(mock)
        println("Is mock: ${details.isMock}")
        println("Is spy:  ${details.isSpy}")

        mock.doit()
        mock.doit()
    }
}

运行makeit时,输出为:

Is mock: true
Is spy:  false
did it: 1
did it: 2

这似乎表明正在创建该主题的某些实例,但绕过了潜在的关键构造函数逻辑。这与“部分模拟”一致,但是代码没有做任何事情来请求这样的事情。

我很惊讶这是默认行为,因为所有文档都强烈警告不要使用部分模拟。我一直无法找到描述mock()返回部分模拟的时间的文档,因此无法弄清楚如何从类中获取“完整模拟”。

所以:

  • Mockito.mock()何时创建局部模拟?
  • Mockito可以为课程创建“完整模拟”吗?还是仅用于界面?
  • 一个人如何要求“完全模拟”?

1 个答案:

答案 0 :(得分:1)

仔细研究源代码并通过反复试验,得出以下结论:

  1. 在模拟类时,Mockito会创建ByteBuddy生成的类的子类的实例,而无需调用构造函数 =>所有成员数据均为默认值。
  2. 打开方法(Java的默认方法;在Kotlin中用open声明):
    • 默认情况下不会调用 并返回默认的返回类型。
    • 配置为when(...).thenCallRealMethod()时将调用
    • 如果在将defaultAnswer设置为CALLS_REAL_METHODS的情况下创建模拟,则会调用
  3. final方法不能被覆盖=>它们将被正常调用,但是它们将看到所有成员数据的默认值。

因此,似乎所有类模拟都是部分模拟,但是由于Java中的默认设置是打开方法,因此它们通常看起来像常规模拟。默认情况下,它们是有效个常规模拟。

由于默认情况下方法为final,因此这在Kotlin中很快出现。

知道这是如何工作的,这样可以减少处理类模拟的烦恼!