Reputation: 2090
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.
Upvotes: 5
Views: 35047
Reputation: 6947
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:
Mockito official documentation on spies: http://static.javadoc.io/org.mockito/mockito-core/2.24.0/org/mockito/Mockito.html#13
Tutorial on how to use Mockito.spy
https://www.baeldung.com/mockito-spy
Differences between mock and spy: https://www.toptal.com/java/a-guide-to-everyday-mockito
Upvotes: 6
Reputation: 134664
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)
}
Upvotes: 1