Kotlin-Mockito验证方法调用

时间:2019-02-13 15:08:23

标签: android testing junit kotlin mockito

我正在尝试与Mockito一起编写单元测试。我有一堂课,需要像下面这样进行测试-

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

  fun setName(name: String) { }

  fun setAge(age: Int) { }
}

下面是我的测试班

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

}

这是我的问题

我这样做的时候-

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

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

但是,当我这样做时-

verify(emp, never()).setAge(23)

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

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

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

2 个答案:

答案 0 :(得分:1)

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

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

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

  assertEquals(23, employee.age)
}

答案 1 :(得分:1)

如@kcoppock所述,您的问题包括不当使用模拟程序。您应该使用模拟对依赖项进行存根控制,以控制其行为。

在您的情况下,被测单元是Employee类及其关联的方法。通常,您不想模拟出被测单元,因为您想(从单元测试中)知道您的类是否表现出应有的方式。为此,您将要使用Employee的真实实例,而不是模拟对象。

如果您坚持在verify实例上使用Employee,则可以创建一个spy

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

  assertEquals(23, employee.age)
  verify(emp, times(1)).setAge(23)
}

这里有一些参考资料供进一步阅读:

  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