One of the most common issues for Kotlin, as we talked about in a previous article, is that all classes and functions are closed by default.
This means that if you want to mock a class (something that may be quite common in Java testing), you need to either open it with the reserved keyword open
, or extract an interface.
Both options can be tedious, and the truth is that they are a limitation for Java developers that start using Kotlin.
Luckily, Mockito 2 has removed this restriction, and today I’m going to teach you how to do it.
If you want to start today, I recommend you take a look at my free training, where you will have an hour and a half of content to know what are your next steps to become an expert in Kotlin.
What is the problem?
Imagine that you have a class in Kotlin that looks like this:
class ClosedClass { fun doSomething() { } }
And you want to test that its doSomething
method is called.
The way to do it would be the following:
@Test fun testClosedClass() { val c = Mockito.mock(ClosedClass::class.java) c.doSomething() verify(c).doSomething() }
If you use Mockito 1.x, you’ll get the following error:
Mockito cannot mock/spy following:
– final classes
– anonymous classes
– primitive types
Update dependencies to Mockito 2
As we have said, Mockito 2 is able to mock it all, so we’re going to update the dependency. At the time of writing this article the latest version is 2.8.9. But check it out because they are updating very often lately.
testCompile 'org.mockito:mockito-core:2.8.9'
So now we run our code again, but… it fails again!
Mockito cannot mock/spy because :
– final class
We’re no longer limited to mock anonymous classes or primitive types, but it’s not the same for final classes. Why is this?
This option is still a bit experimental, and requires a manual activation.
Enable the option to mock final classes
To do this, you’ll need to create a file in the test/resources/mockito-extensions
folder called org.mockito.plugins.MockMaker
:
It’s a simple text file, in which you have to write:
mock-maker-inline
Nothing else.
Now you can run the test again, and you’ll see that it runs smoothly. Great!
Mocking Properties
You can also mock properties with no issues. If we change the code of the class to this, for example:
class ClosedClass(val prop: Int) { fun doSomething() { } }
Now let’s mock the value of the property:
@Test fun testClosedClass() { val c = Mockito.mock(ClosedClass::class.java) `when`(c.prop).thenReturn(3) val prop = c.prop assertEquals(3, prop) }
I’m asking it to return 3 when it’s called, and later, I check that the value is correct.
You can also check that a property has been called with:
verify(c).prop
Conclusion
As you can see, all the limitations have disappeared thanks to the latest version of the most popular mocking library.
So excuses are over! You can now write all your tests using Kotlin.
If you like what you’ve seen, I encourage you to sign up for my free training, where I’ll tell you everything you need to learn about how to create your own Android Apps in Kotlin from scratch.
Hi, Thanks for your great posts! after adding the file org.mockito.plugins.MockMaker, the unit tests stop running from the command line (not “./gradlew testDebugUnitTest” nor “./gradlew test”.
If I remove this file, it runs the tests from command line (the tests are failed since its can’t mock final classes, but at least it runs). any suggestions? Thanks
Hi Mockito still pretty Javi-sh, check out true Kotlin alternative http://mockk.io
You can also add this to your dependencies and it has the same effect:
testImplementation ‘org.mockito:mockito-inline:2.13.0’
True, in fact I explain it like this in the book. I think it’s much easier. I need to update this article. Thanks for your comment!
Hi, Lidor. Did you find any solution?
Thanks for such a wonderful article. It really saved my time.
Glad to know! You’re welcome
Thanks a lot, you save my life!
Always glad to help!
Great article works fine but I am getting NullPointerException for one of my java test class.
I’m unable to mock final class after adding MockMaker class, any help?
You can try to add the `mockito-inline` library instead. It does the same, but the library does it for you.