Categories: androidioskmpkotlin

Kotlin Multiplatform Testing: Unit, Integration, and Platform-Specific Strategies

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 testingintegration testing, and mocking strategies to ensure your KMP apps work flawlessly across platforms.



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"))  
            }  
        }  
    }  
}  

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))  
    }  
}  

Run Tests:

  • In Android Studio: Right-click commonTestRun 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())  
    }  
}  

Dependency:

androidTestImplementation("junit:junit:4.13.2")  

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))  
    }  
}  

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")  
}  

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))  
    }  
}  

Koin for Dependency Injection

Simplify testing with Koin’s lightweight DI framework.

Setup Koin:

dependencies {  
    implementation("io.insert-koin:koin-core:3.4.0")  
}  

Example:

class UserRepositoryTest : KoinTest {  
    private val repository: UserRepository by inject()  

    @Test  
    fun testUserFetching() {  
        assertEquals("Alex", repository.getUser(1).name)  
    }  
}  

Key Takeaways

  1. Use kotlin.test for shared logic unit tests.
  2. Platform tests require JUnit (Android) or XCTest (iOS).
  3. MockEngine simplifies API integration testing.
  4. MockK and Koin streamline mocking and dependency injection.
  5. Check KMP vs Flutter

Saiful Alam Rifan

Mobile Application Developer with over 12 years of experience crafting exceptional digital experiences. I specialize in delivering high-quality, user-friendly mobile applications across diverse domains including EdTech, Ride Sharing, Telemedicine, Blockchain Wallets, and Payment Gateway integration. My approach combines technical expertise with collaborative leadership, working seamlessly with analysts, QA teams, and engineers to create scalable, bug-free solutions that exceed expectations. Let's connect and transform your ideas into remarkable mobile experiences.

Recent Posts

Start Building KMP App with Material Design 3 Expressive – 2025

Introduction: Transform Your Cross-Platform Development with Material Design 3 Are you ready to revolutionize your… Read More

1 month ago

Google I/O 2025: A New Era for KMP and Android, Powered by AI

Alright, fellow developers, let's dive into Google I/O 2025. If you blinked, you might have… Read More

3 months ago

What’s New in Jetpack Compose 1.8: Autofill, Text, Visibility & More (2025)

Jetpack Compose 1.8 rolls out handy features like Autofill integration, slick Text enhancements including auto-sizing… Read More

5 months ago

Reified Keyword in Kotlin Explained: Unlock Type Safety

 Reified Keyword in Kotlin: Simplify Your Generic Functions Kotlin's reified keyword lets your generic functions know the… Read More

5 months ago

Android Studio Cloud: Develop Android Apps Anywhere (2025)

Android Studio Cloud: Ditch the Setup, Code Anywhere (Seriously!) Alright, fellow Android devs, gather 'round… Read More

5 months ago

Firebase Studio & Google’s AI Dev Tools Guide

Firebase Studio is a new cloud-based platform for building AI-powered apps, launched at Google Cloud… Read More

5 months ago