Mocking Kotlin with Mockito
Hadi HaririThe un-mockable
Given that by default Kotlin classes and functions are final (i.e, you need the open
modifier to be able to inherit from them), when trying to mock behaviour in tests, you’re often left with no choice other than to declare these open
or introduce interfaces solely for the purpose of testing. Neither of these are really great.
For instance, given the following code
class LoanCalculator {
fun calculateAmount(customerId: Int): Double {
return 100.0 * customerId
}
}
and a class that uses the above
class LoanService(val loanCalculator: LoanCalculator) {
fun authoriseCustomerLoan(customerId: Int): Double {
if (customerId != 0) {
return loanCalculator.calculateAmount(customerId)
}
return 0.0
}
}
If I want to be able to mock the calculateAmount
function, I could write something like the following
@Test
fun authoriseCustomerLoan() {
val mockLoanCalculator = mock(LoanCalculator::class.java)
`when`(mockLoanCalculator.calculateAmount(3)).thenReturn(300.0)
val loanService = LoanService(LoanCalculator())
val amount = loanService.authoriseCustomerLoan(3)
assertEquals(300.0, amount)
}
but on running it, Mockito would complain indicating that it cannot mock a class/method that is final.
MockMaker
Mockito 2 solves this. With the recent release of version 2, one of the big changes is the ability to mock the un-mockable. In other words, you can mock final classes in Java and consequently all classes and member functions in Kotlin.
In order to take advantage of this feature, you write your code in exactly the same way you would for mocking an open class/function. However, you need to perform an additional step which basically consists in creating a file named org.mockito.plugins.MockMaker
and placing this under the resources/mockito-extensions
directory in your test folder[1].
The file contains a single line:
mock-maker-inline
If you’re using Gradle, you can also have it generate the file for you.. You can download the sample project I’ve created from GitHub
Finally, a big kudos to Rafael for his work in making this possible!
[1] This feature is still new and plans are to make it easier to configure as they receive feedback on its usage.