Why I’m switching from Mockito to Mockk

For the longest time, Mockito has been recognised as the go-to mocking framework for Android, but more recently, Mockk has been gaining more popularity especially with the shift to Kotlin and the adoption of Coroutines.

If you’re not already familiar with it, Mockk is a mocking framework built specifically for Kotlin. Unlike Mockito Kotlin which is an extension of Mockito to help it work better with Kotlin, Mockk was built from the ground up for mocking Kotlin classes.

For a long time, I never had a compelling reason to pick Mockk over Mockito which I was already very familiar with, that is, until this morning.

I came to realise that Mockk offers flexibility and allows better testing practices where Mockito simply falls short on.

In this post, I’ll explain exactly what those are.

 

Mockk doesn’t provide answers by default

Yes, I’m saying this as an advantage. I’m of the mindset that if you have to resort to default answers for your mocks, there’s something fundamentally wrong with your test.

There are of course specific situations where you might absolutely need to (that’s why the functionality’s there), but I speak for the majority of cases.

With Mockito, by default, if you didn’t stub the method of a mocked class and called it during a test, no exception would be thrown and the test would continue as normal. This means that you could potentially be making unwanted calls in your methods without knowing it.

But even worse than that, the relaxed methods would return null which could introduce an unintentional test scenario and report false positives.

With Mockk however, you’d get an error like the one above. No answer found. If we didn’t want to call getString in the method we were testing, we’d find out this way.

private val resourceProvider: ResourceProvider = mockk {
    every { getString(any()) } returns ""
}

So Mockk encourages you to be fully aware of the methods being accessed in your test and stub them.

But Mockk specifically allows you to relax unit functions

Relaxing unit functions as a good practice does make me feel relaxed

Mockk allows you to relax all functions of a mocked class, but that’s not what we want. Relaxing only the unit functions though? Now that’s a different story.

private val persistentStorageWriter: PersistentStorageWriter = mockk(relaxUnitFun = true)

The relaxUnitFun provides a ‘no specific behaviour’ creation for functions of that mock that have a return type of Unit

What’s the reason I like this? Unit functions don’t have a return type we necessarily make use of, unlike the false nulls we’d get with functions returning other types. This means we are safe from any unintentional null-path testing.

And this also just makes our tests much more concise and easier to write.

@Test
fun givenAlreadyOwnedResult_whenHandlePurchaseResult_thenDisplaySnackbar() {
    val purchaseResult = BillingInteractor.PurchaseResult.AlreadyOwned

    viewModel.handlePurchaseResult(purchaseResult)

    verify { snackbarNavigator.displaySnackbar(R.string.purchase_dialog_already_owned_message) }
}

Thanks to relaxUnitFun, we don’t have to manually stub snackbarNavigator.displaySnackbar which has little need for stubbing.

The combined functionality of not having relaxed mocks by default but also being able to use relaxUnitFun allows us to enjoy the best of both worlds when it comes to having an easier time writing tests whilst also doing our tests the right way.

 

 

Coroutine Support

Mockito doesn’t have any built-in coroutine support, so if you wanted to test coroutines with Mockito, you’d have to use runBlockingTest. I don’t find this ideal, as debug breakpoints simply don’t work in a runBlockingTest, and it’s also boilerplate.

@Test
fun whenCtaButtonPressed_thenLaunchBillingFlow() {
    coEvery { billingInteractor.connectIfNeeded() } returns true
    
    viewModel.onCtaButtonPressed()

    coVerify { billingInteractor.launchBillingFlow() }
}

Mockk has two very useful functions when it comes to testing coroutines: coEvery and coVerify.

Their purpose is very clear as well. They’re the same as every and verify but they work for suspend functions.

private val billingInteractor: BillingInteractor = mockk(relaxUnitFun = true) {
    coEvery { connectIfNeeded() } returns true
    coEvery { getPremiumSkuDetails() } returns SkuDetails("")
}

As an added bonus, Mockk allows you to stub directly within the creation of the mock which can get rid of the need of a @Before method in many cases.

I think Mockito can do this as well, but I’ve definitely not seen it been used so I’m led to believe it’s simply not powerful or flexible enough to be used unlike Mockk’s version of it.

Mockk can mock static methods

It’s debatable whether mocking static methods is a good practice or not, I think generally it’s best to avoid but there are test-cases where it can’t easily be avoided.

You might be writing instrumented tests closely coupled with Android (or other 3rd-party) code, or you might simply be testing legacy code which wasn’t written in the best ways, is static, and is too much effort in the present moment to refactor properly.

@Before
fun mockAllUriInteractions() {
    mockkStatic(Uri::class)
    every { Uri.parse("http://test/path") } returns Uri("http", "test", "path")
}

In which case, mockkStatic opens that possibility and you can start stubbing static methods of that class.

As far as I know, Mockito doesn’t provide any way to mock static methods.

Conclusion

Mockk was built from the ground-up specifically for Kotlin, and it really shines through in its coroutine and static support.

And while these 3 reasons are definitive reasons I can say now for why I think Mockk has the edge over Mockito, I have high hopes that as I continue to use it, I’ll discover more about the framework that makes it shine even more.

It was Shopshop Shopping List I was writing unit tests for when I realised the advantages Mockk has over Mockito and gave me the reason for writing this article.

https://github.com/ericdecanini/ShopshopShoppingList

The project currently uses a combination of Mockito and Mockk, as I’ve been on both sides of the coin as to which mocking framework I prefer.

I used Mockito in classes such as HomeViewModelTest and SQLiteShoppingListRepositoryTest

I used Mockk in classes such as MainViewModelTest and UpsellViewModelTest

If you want to see some tests in either framework, I recommend you go check it out.

On another note, Shopshop is an app I’ve been working very hard on and I just released its beta version last week, so go check it out if you fancy trying out a shopping list app focused on speed and beauty.

And as always, happy coding ༼ つ ◕_◕ ༽つ

 

 

 

Subscribe to the Newsletter