Random thoughts about Kotlin Testability — Part 1 from Mark Allison
First of all, I really enjoy reading the stylingandroid.com blog and I recommend it to everyone. There are often (or most of the time) really cool tricks, features or tutorials about Android and programming in general.
Whatever. Last Friday (he always publish a blog on Friday) he wrote an article about Kotlin Testability. I’m a test addict so the title sounds really promised to me. Unfortunately it wasn’t.
1. mock-maker-inline
He mentioned it in the last part of the article. The problem is that Kotlin methods/classes/proerties etc. are final by default. Which means you can’t easily mock this types with Mockito by default. But there is help. Mockito brings the option (not the JetBrains guys Mark 😉) to change it with the mock-maker-inline
.
I really don’t recommend that. It just slows down your tests a lot! I don’t know why. Maybe it is because of the “subclassing” (whatever this means). But I have just made the experience that it is slow.
Testing should be as fast a possible. Otherwise you get annoyed of the long running tests and finally to decide to just don’t test…
Other solutions:
* JetBrains brings a optional allOpen plugin
which make methods/classes/properties etc. not final if declared with an annotation.
* Use dependency injection like he described in his article
2. The factory which is a Singleton
To fix his problem he have to create a factory.
Of course, it is a factory “by design”. But it isn’t a factory by the view of Kotlin.
This factory is a Singleton.
Only because it is easy to create Singletons in Kotlin you shouldn’t overuse it!
Other (the Kotlin) solution:
* Use a companion object
instead of a Singleton.
Summary:
He using — also my recommended way — dependency injection (or better: constructor injection) but make the constructor only visible for package classes. Which is nothing more than having like that in Java:
public DateStringProvider() {
this(new DefaultFactory());
}@VisibleForTesting(otherwise = VisibleForTesting.NONE)
DateStringProvider(Factory factory) {
mFactory = factory
}
This is the right way to do it and I (or maybe you as well?!) do it already, right?! 😉