A how-to guide on writing tests within Kotlin Multiplatform.
Code quality is very important. Testing is a huge part of code quality. You want to ensure the code you write behaves as expected. It also needs to work under a variety of conditions.
I use the Given When Then approach to testing across all our Small, Medium and Large tests. It's a useful way of structuring tests. I also rely on mocking within my tests. I want to ensure the only thing I am testing is the class(es) I intended.
Testing within Kotlin Multiplatform is well supported and will feel very familiar.
implementation "org.jetbrains.kotlin:kotlin-test-common:$kotlin_version" implementation "org.jetbrains.kotlin:kotlin-test-annotations-common:$kotlin_version"
Kotlin provides some common test dependencies to enable you to write multiplatform tests. Meaning you only have to write your tests once, rather than writing platform-specific tests.
Consider this simple repository:
We have two methods, both providing a way of getting a User. One provides a suspend function and one provides a callback approach. The callback returns an IOResult, which encapsulates success and error states. My Android app will use the suspend function, and my iOS app will use the callback function. Suspend functions aren't yet supported on iOS.
So we want to be able to write 4 tests:
- remoteFailure__getUser__error - remoteSuccess__getUser__success - callback_remoteFailure__getUser__error - callback_remoteSuccess__getUser__success
following the naming convention of given__when__then. These will encapsulate all the possible scenarios for these methods.
We will need to be able to mock our UserRemote. Currently there is no framework available for mocking classes within both Android and iOS. Mockk is on its way to supporting JS and Native (iOS) but is not yet complete.
So, we must create our own mock manually. This approach might be somewhat familiar to iOS developers.
We create a class which implements the UserRemote interface. It provides the ability to define the getUser behaviour by providing a function var. So, within a test we can set whenGetUser and provide some behaviour.
To test a suspend function we need to add the coroutines test dependency.
Adding this expect and actual utility makes it easy to run our common test suspend functions.
To be able to assert on our callback results we need to be able to mock them.
This mock captures the params which the callback gets invoked with.
Using these components, we are now able to write our tests.
To create a mock of User we can write a little extension method:
Kotlin Multiplatform common test code can be a little cumbersome to write. Especially for an Android developer who makes use of frameworks like Mockito. But the ability to test commonly is very powerful. It will reduce your overall testing workload.
Check out Alistair's other musings on all things Kotlin:
Pinning a certificate for iOS here
Coding and culture in Kotlin here
Perhaps you'd be interested in strategies for multiplatform project structure here
Or if you're completely new to Kotlin, have a read of our overview here
Search over 200 blog posts from our team
Subscribe to our monthly digest of blogs to stay in the loop and come with us on our journey to make things better!