Testing is the backbone of reliable cross-platform apps. Kotlin Multiplatform (KMP) lets you write tests once for shared logic and adapt them for Android, iOS, and web. This chapter covers unit testing, integration testing, and mocking strategies to ensure your KMP apps work flawlessly across platforms.
Table of contents
1. Unit Testing Shared Code
Test shared business logic in commonTest
using Kotlin’s built-in kotlin.test
library.
Setup Dependencies
Add to build.gradle.kts
:
kotlin {
sourceSets {
val commonTest by getting {
dependencies {
implementation(kotlin("test"))
}
}
}
}
Code language: JavaScript (javascript)
Example: Testing a Utility Function
// commonMain
fun add(a: Int, b: Int): Int = a + b
// commonTest
import kotlin.test.Test
import kotlin.test.assertEquals
class MathTests {
@Test
fun testAddition() {
assertEquals(5, add(2, 3))
}
}
Code language: JavaScript (javascript)
Run Tests:
- In Android Studio: Right-click
commonTest
→ Run Tests. - Terminal:
./gradlew test
.
2. Testing Platform-Specific Code
Android (JUnit)
Test Android-specific code in androidTest
:
// androidMain
actual fun getPlatformName(): String = "Android"
// androidTest
import org.junit.Test
import kotlin.test.assertEquals
class AndroidPlatformTests {
@Test
fun testPlatformName() {
assertEquals("Android", getPlatformName())
}
}
Code language: JavaScript (javascript)
Dependency:
androidTestImplementation("junit:junit:4.13.2")
Code language: CSS (css)
iOS (XCTest)
Test iOS code in iosTest
:
// iosMain
actual fun getPlatformName(): String = "iOS"
// iosTest
import XCTest
class IosPlatformTests: XCTestCase {
func testPlatformName() {
XCTAssertEqual(getPlatformName(), "iOS")
}
}
Run iOS Tests:
- Xcode or
./gradlew iosTest
.
3. Integration Testing
Verify end-to-end functionality, like API calls, using MockEngine to simulate responses.
Example: Testing API Calls
// commonMain
suspend fun fetchUserData(client: HttpClient): String {
return client.get("https://api.example.com/user").body()
}
// commonTest
import io.ktor.client.engine.mock.*
import kotlin.test.Test
class NetworkingTests {
@Test
fun testFetchUserData() = runTest {
val mockEngine = MockEngine {
respond(
content = """{"id":1,"name":"Alex"}""",
status = HttpStatusCode.OK
)
}
val client = HttpClient(mockEngine)
assertEquals("""{"id":1,"name":"Alex"}""", fetchUserData(client))
}
}
Code language: JavaScript (javascript)
Why MockEngine?
- Simulates API responses without network calls.
- Speeds up tests and avoids external dependencies.
4. Mocking & Dependency Injection
MockK for Mocking
Mock dependencies to isolate components during testing.
Setup MockK:
dependencies {
commonTestImplementation("io.mockk:mockk-common:1.13.8")
}
Code language: JavaScript (javascript)
Example:
interface UserRepository {
suspend fun getUser(id: Int): User
}
class UserServiceTest {
@Test
fun testFetchUser() = runTest {
val mockRepo = mockk<UserRepository>()
coEvery { mockRepo.getUser(1) } returns User(1, "Alex")
val service = UserService(mockRepo)
assertEquals("Alex", service.fetchUser(1))
}
}
Code language: PHP (php)
Koin for Dependency Injection
Simplify testing with Koin’s lightweight DI framework.
Setup Koin:
dependencies {
implementation("io.insert-koin:koin-core:3.4.0")
}
Code language: JavaScript (javascript)
Example:
class UserRepositoryTest : KoinTest {
private val repository: UserRepository by inject()
@Test
fun testUserFetching() {
assertEquals("Alex", repository.getUser(1).name)
}
}
Key Takeaways
- Use
kotlin.test
for shared logic unit tests. - Platform tests require JUnit (Android) or XCTest (iOS).
- MockEngine simplifies API integration testing.
- MockK and Koin streamline mocking and dependency injection.
- Check KMP vs Flutter
- Link to Koin documentation for authority.