Kotlin - Mockito verify method calls

15,129

Solution 1

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

Solution 2

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)
}
Share:
15,129
Anirudh
Author by

Anirudh

Movie geek. Voracious reader. Cricket buff. Avid Programmer

Updated on June 04, 2022

Comments

  • Anirudh
    Anirudh almost 2 years

    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.