Kotlin - Mockito 验证方法调用

Ani*_*udh 5 testing junit android mockito kotlin

我正在尝试使用 Mockito 编写单元测试。我有一个类需要进行如下测试-

open class Employee {
  fun setDetails(name: String, age: Int) {
    setName(name)
    setAge(age)
  }

  fun setName(name: String) { }

  fun setAge(age: Int) { }
}
Run Code Online (Sandbox Code Playgroud)

下面是我的测试课

class EmployeeTest {
  @Mock
  lateinit var emp: Employee

  @Before
  fun setup() {
    MockitoAnnotations.initMocks(this)
  }

  @Test
  fun testDetail() {
    emp.setDetails("Henry", 23)

    verify(emp, times(1)).setAge(23)
  }

}
Run Code Online (Sandbox Code Playgroud)

这是我的问题

当我做 -

verify(emp, times(1)).setAge(23)
Run Code Online (Sandbox Code Playgroud)

这给了我成功,因为 setAge 在 Employee.kt 的 setDetails() 中被调用一次。所以这对我来说很好用

但是,当我这样做时——

verify(emp, never()).setAge(23)
Run Code Online (Sandbox Code Playgroud)

即使在 setDetails() 中调用该方法,这仍然使我成功。这个测试用例不应该失败吗?

请帮助我理解这一点。我一直无法弄清楚为什么会发生这种情况。

编辑 这对我有用,我使用间谍而不是模拟。但是,我还必须在 Kotlin 中将这些方法声明为 open。

VIN*_*VIN 5

正如 @kcoppock 所提到的,您的问题包括对模拟的不当使用。您应该使用模拟来消除依赖关系,以控制它们的行为。

在您的情况下,被测试的单元是Employee类及其关联的方法。一般来说,您不想模拟被测试的单元,因为您想(从单元测试中)知道您的类是否按其应有的方式运行。为了实现这一点,您需要使用 的真实实例Employee,而不是模拟实例。

如果您坚持verifyEmployee实例上使用,您可以创建一个spy.

@Test
fun setDetails_adjustsAge() {
  val employee = spy(Employee())
  employee.setDetails("Henry", 23)

  assertEquals(23, employee.age)
  verify(emp, times(1)).setAge(23)
}
Run Code Online (Sandbox Code Playgroud)

以下是一些供进一步阅读的参考资料:

  1. Mockito关于间谍的官方文档: http://static.javadoc.io/org.mockito/mockito-core/2.24.0/org/mockito/Mockito.html#13

  2. 如何使用教程Mockito.spy https://www.baeldung.com/mockito-spy

  3. 模拟和间谍之间的区别:https://www.toptal.com/java/a-guide-to-everyday-mockito


kco*_*ock 1

所以你的问题是你实际上不想使用模拟。当您使用模拟时,您需要为在该实例上调用的任何方法定义行为。因此,当您调用 时emp.setDetails("Henry", 23),该方法没有实现,因此什么也没有发生。类中定义的行为Employee将不会被使用,因为它emp只是一个Employee没有定义任何行为的假实例。

对于您的测试场景,您应该更喜欢使用真实实例,并验证最终结果而不是内部行为。例如:

@Test
fun setDetails_adjustsAge() {
  val employee = Employee()
  employee.setDetails("Henry", 23)

  assertEquals(23, employee.age)
}
Run Code Online (Sandbox Code Playgroud)