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:


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:


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?


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

0 0 votes
Article Rating

Leave a Reply

0 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
0
Would love your thoughts, please comment.x
()
x