Background:
I had a Groovy class which has a method that relies on an another Kotlin method imported from a dependency as the following:
class DependencyClass {
fun remoteMethod(param1: String, param2: Int, param3: Boolean): String {
// Method logic
return "result"
}
}
// Groovy class
class MyClass {
// Google guice injection
@Inject
private DependencyClass depClassObj
void myMethod(input) {
// Call with 3 parameters
def result = depClassObj.remoteMethod("example", 42, true)
// Other logic...
}
}
The tests of my Groovy class methods are written in Kotlin as the following:
@Test
fun `test myMethod which calls anotherMethod in DependencyClass`() {
// Mock & bind etc..
val depClassObjMock = mock<DependencyClass>()
// Step 3: Define behavior for myMethod using matchers
whenever(depClassObjMock.remoteMethod( any(), any(), any() )).thenThrow(NullPointerException)
myClassMock.myMethod()
// TestUtil class which runs the methods...
assertThrows<NullPointerException>(flowRunner.runFlow("myClassMock.myMethod"))
}
Problem:
The Dependency that I was relying on got updated, as the remoteMethod()
started to take 4 parameters instead of 3, where the 4th parameter is nullable as the following:
class DependencyClass {
fun remoteMethod(param1: String, param2: Int, param3: Boolean, param4: String? = null): String {
// Method logic
return "result"
}
}
Now all my tests started to fail due to an error that looks:
Invalid use of argument matchers!
4 matchers expected, 3 recorded:...
What have I tried:
First try (didn’t work)
I tried editing the tests by passing a new matcher for the new parameter as anyOrNull()
or eq(Null) or
isNull()` as the follwing:
whenever(depClassObjMock.myMethod( any(), any(), any(), anyOrNull() )).thenThrow(NullPointerException)
but now the whenever
or when
statement doesn’t match the myMethod schema causing the tests to do the actual logic of the myMethod (without mocking).
as
depClassObjMock.remoteMethod(any(), any(), any(), anyOrNull()) // takes 4 parameters
!==
depClassObj.remoteMethod("example", 42, true) // takes 3 parameters, even if the 4th is nullable it's not pointing for the whenever statement with the 4 parameters.
Second try (worked)
I had to edit the logic inside `myMethod() to make the tests work (which is not a good practice as I recall) as the following:
def result = depClassObj.remoteMethod("example", 42, true, null)
Ask:
-
Is there any way to test kotlin methods with nullable parameters without editing the actual logic (only edit the tests) ?
-
Does this issue has anything to do with the fact that we are calling a Kotlin method from a Groovy method then testing the groovy flow in Kotlin tests ?
-
How testing methods with nullable parameters usually get done in Kotlin ?
-
How Mockito usually maps the whenever / when statements to the original methods ?
Feel free guys to answer any question of the 4. You don’t have answer them all.