Using mockito with kotlin - part 2
In a previous post I looked at the problems I had been having using Mockito in a Kotlin project and the small helper functions that could make things easier. At the end of that post I said that I didnt have a good solution to the problems of using a captor. I really didn’t want to add another dependency like mockito-kotlin. Well it turns out there is a solution.
Argument captors
The problem is that if a method does not take a nullable parameter then an error is generated when the test is run.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
@Test
fun draw_a_track_with_captor() {
// arrange
val displayTrack = setupDisplayTrackWithTwoPoints()
// act
presenter.displayTrack(DISPLAY_TRACK_ID)
// assert
val captor: ArgumentCaptor<Position> = ArgumentCaptor.forClass(Position::class.java)
Mockito.verify(mockview, Mockito.times(1)).resetMapToPosition(captor.capture())
val capturedPositions: List<Position> = captor.allValues
assertThat("there should only be one position", capturedPositions.size, `is`(1))
}
When we run the test we get this error
java.lang.IllegalStateException: captor.capture() must not be null
at com.andrewandderek.trailblazer.unittests.ui.main.DisplayTrackTests.draw_a_track_with_captor(DisplayTrackTests.kt:93)
...
org.mockito.exceptions.misusing.InvalidUseOfMatchersException:
Invalid use of argument matchers!
This is because the signature for resetMapToPosition() look like this
fun resetMapToPosition(position: Position)
If the method took a Position?
then all would be well, but as captor.capture() returns null
the test will not run.
Fixing argument captors
I found this one line function on this very useful page Using this function means that we can overone the captor problem without any additional library.
1
2
3
4
object MockitoHelper {
// use this in place of captor.capture() if you are trying to capture an argument that is not nullable
fun <T> capture(argumentCaptor: ArgumentCaptor<T>): T = argumentCaptor.capture()
}
The test now look like this
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
@Test
fun draw_a_track_with_captor() {
// arrange
val displayTrack = setupDisplayTrackWithTwoPoints()
// act
presenter.displayTrack(DISPLAY_TRACK_ID)
// assert
val captor: ArgumentCaptor<Position> = ArgumentCaptor.forClass(Position::class.java)
Mockito.verify(mockview, Mockito.times(1)).resetMapToPosition(MockitoHelper.capture(captor))
val capturedPositions: List<Position> = captor.allValues
assertThat("there should only be one position", capturedPositions.size, `is`(1))
assertThat("incorrect value", capturedPositions[0].notes, `is`("POSITION_NOTES_1"))
}