简体   繁体   中英

Kotlin - Mockito verify method calls

I'm trying my hand with Mockito for writing unit test's. I have a class that needs to be tested like below-

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

  fun setName(name: String) { }

  fun setAge(age: Int) { }
}

Below is my test class

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

}

Here is my problem

When I do -

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

This give's me a success, because setAge is called once in setDetails() of Employee.kt. So that works fine for me

But, when I do-

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

This still gives me a success, even though the method is called in setDetails(). Shouldn't this test case fail?

Please help me understand this. I haven't been able to figure out why this happens.

EDIT Here's what worked for me I used a spy instead of a mock. However, I had to also declare the methods as open in Kotlin.

So your issue here is that you don't actually want to use a mock. When you use a mock, you're required to define the behavior for any method that you call on that instance. So when you call emp.setDetails("Henry", 23) , there is no implementation for that method so nothing happens. The behavior defined in the Employee class will not be used, as emp is just a fake instance of Employee that has not defined any behavior.

For your test scenario, you should prefer to use a real instance, and validate the end result rather than the internal behavior. For instance:

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

  assertEquals(23, employee.age)
}

As mentioned by @kcoppock, your question includes an improper use of a mock. You should be using mocks to stub out dependencies in order to control their behavior.

In your case, the unit under test is the Employee class and its associated methods. In general, you do not want to mock out the unit under test because you want to know (from your unit test) if your class is behaving the way it should. To accomplish that, you'll want to use a real instance of an Employee , and not a mock.

If you are insistent on using verify on the Employee instance, you can create a spy .

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

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

Here are some references for further reading:

  1. Mockito official documentation on spies: http://static.javadoc.io/org.mockito/mockito-core/2.24.0/org/mockito/Mockito.html#13

  2. Tutorial on how to use Mockito.spy https://www.baeldung.com/mockito-spy

  3. Differences between mock and spy: https://www.toptal.com/java/a-guide-to-everyday-mockito

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM