I stumbled upon a number of papercuts when trying to use Mockito together with Kotlin which I wanted to discuss with the community.
a) Mockito.any(…) and other matchers often return null
To me, this seems to effectively block using Mockito with Kotlin.
See the following example:
import org.junit.Test as test
import java.math.BigDecimal
import org.mockito.Mockito.doNothing
import org.mockito.Mockito
import org.mockito.Matchers
open class DependencyOfCUT {
fun d(aParam: BigDecimal) {
//do something
}
}
class CUT {
fun testedMethod(d: DependencyOfCUT) {
d.d(BigDecimal.ZERO)
}
}
class TheTest {
test fun aTest() {
val d = Mockito.mock(javaClass<DependencyOfCUT>())!!
//added !! for illustration purpose only: // >>>> Matchers.any will almost always return <null> which causes NPEs at runtime <<<<
// Other mockito matchers will also effectively return ‘null’
Mockito.doNothing().when(d).d(Matchers.any(javaClass<BigDecimal>())!!)
CUT().testedMethod(d)
}
}
>>>> Matchers.any will almost always return <null> which causes NPEs at runtime <<<<
b) escaping syntax for when/is required all the time
The same applies to heavy users of hamcrest (independent of mockito)
assertThat(a.getB(), is(expected))
This is inconvinient and hinders readability. Maybe we can come up with a more readable alternative? Typing the sign interrupts the flow since it is intended to be put on top of the next letter. If I type "" + “i” I’ll end up with ì (accent-I).
c) The need for open classes/methods
Mocking frameworks such as Mockito very often rely on non-final classes/methods. If a class is used by some other class and the other class is unit-tested, it seems we have to declare it open. The same applies to its methods. At the end, almost all classed need to be open. Does it make sense to default to final (non-open) for tests?
Kotlin strives for a good Java Interoperability which is necessary to be accepted. I would appreciate if we could use existing libraries (i.e. Mockito) painlessly. Otherwise we end up reimplementing proven Java libraries - Mockito is just an example - in Kotlin.
I would agree that some reimplementation is desireable to take advantage of advanced APIs which are not possible in Java. I would appreciate it if we could just re-use existing libs.
a) If you are OK with the risk of having an exception at runtime, annotate Mockito methods as @NotNull
b) Use rename on import to work around the naimng problem
I'd say that introducing an interface or using a trait just for testing/mocking sounds odd. Why introduce an artificial artifact which needs to be subclassed when I can do without?
What would you to with (Kotlin-) libraries which you cannot alter?
From a design point-of-view traits are something different than classes since (correct me if I’m wrong) you cannot just instantiiate traits.
Correct, these different opinions are part of thousands of existing libraries which we cannot change. Or is there a way to make a class dynamically extend/implement a trait similar to extension functions?
Correct, these different opinions are part of thousands of existing libraries which we cannot change. Or is there a way to make a class dynamically extend/implement a trait similar to extension functions?
Wouldn't JMockit help? They claim to be able to mock about everything, including final classes and final methods.
There's also Powermock/Powermockito which also claims that they can do that.
But Andrey’s suggestion to introduce a trait is different (if I got it right). Just assume that DependencyOfCUT is part of an external library. Since DependencyOfCUT does not implement an Interface/Trait with method d as expected by CUT we would need to introduce the interface/trait and a way to make DependencyOfCUT implement it. I guess it is possible to do that using byte-code modification. HoweverCUT.testedMethod would have to take this Interface as an parameter instead of DependencyOfCUT, so we need that in production code.
Since I would prefer not to use byte-code enhancements in my production code, this is not an acceptable way.
Solution 2 would be to wrap the external DependencyOfCUT behind an Interface/Trait which is implemented by a project-specific class which is in turn delegating to the real DependencyOfCUT.
Essentially this means wrapping every external dependency which does not follow the “Interface for everything” paradigm. In my opinion this is impractical for a non-trivial project.
The strategy I have used is to create an interface (or trait), then create an implementing class that wraps your dependency. No need for byte-code mods.
Using Mockito with matchers is impossible since they return null regardeless of the kotlin signature allowing or disallowing null. This either results in a NPE or a compiler error (as explained in earlier posts).
Is there someone who has sucessfully used other mock libraries with Kotlin?
Sorry I wasn't suggesting it was different, but the benefit you gain is decoupling from the implementation and potentially a better design. If this decoupling doesn't serve you well then possibly an integration test or some sort of double not created by Mockito.
My personal take on this topic, as someone who has a lot experience with mocking libraries (I created JMockit):
Kotlin should have its own testing libraries, including a JUnit/TestNG equivalent, a mocking library, and a coverage tool. Trying to use tools that were created and only meant for the Java language (even if possible) is not going to cut it. JMockit, for instance, makes several assumptions (use of instance initialization blocks, use of JUnit or TestNG, etc.) that won’t translate well to Kotlin, if at all. The same for libraries like Mockito having method names like when which are reserved keywords in Kotlin.
In general, mocking is not a practice that is conducive to good automated tests. It should be used sparingly. Integration tests with no mocking tend to be much better. I say that as someone who has written thousands of JUnit/TestNG tests since 2004, with and without mocking. So, your best choice (whatever the programming language) is to not mock.
While i appreciate your efforts with JMockit, I too have been writing tests for years and saying that you should not mock or use integration tests is an anti pattern or rather will make your tests less maintainable in the long run. ‘Unit’ tests should be testing a unit. Not a number of units. Mocking helps achieve this as you control the behaviour of dependent classes. The testing pyramid also talks about where you should focus your tests.
Integration tests are useful and should be in your test suite, but primarily to keep your tests maintainable and quick, unit tests are a much better option than having a large set of integration tests.
Well this tends to be a question of philosophy and there are good reasons for both sides. Yes integration tests are harder to maintain, but are also the sort of test catching the more severe bugs (well depending on your type of project). I’ve been working both on games and “normal” business applications and I agree with you that for the business application I was working on unit tests were the better choice most of the time.
In games on the other hand, there are a lot of things where unit tests simply make no sense. Behavior is not defined on a unit level but in the interaction between different units, so integration tests become much more important while unit tests become mostly (IMO) a waste of time.