Testing, Tooling & Publishing
Write tests once, run everywhere
Because your logic lives in commonMain, you write tests once in commonTest and they run on every target — verifying the exact code both apps use.
// commonTest
class UserRepositoryTest {
@Test
fun parsesUsers() = runTest {
val repo = UserRepository(fakeApi, fakeDb)
val users = repo.getUsers()
assertEquals(2, users.size)
}
}
Use fakes/mocks for the API and database (easy thanks to interfaces + DI) so tests are fast and reliable. runTest handles coroutines in tests.
The KMP ecosystem to know
- Ktor — networking.
- kotlinx.serialization — JSON.
- kotlinx.coroutines — async & Flow.
- SQLDelight — database.
- Koin — dependency injection.
- kotlinx-datetime — dates and times.
- SKIE — better Swift interop.
- Compose Multiplatform — optional shared UI.
These are the building blocks of most production KMP apps.
Building and shipping
Crucially, publishing is unchanged — you ship two normal apps:
- Android — build a signed App Bundle (
.aab) in Android Studio and upload to the Google Play Console, exactly as with any Android app. The shared logic is already inside. - iOS — open the iOS app in Xcode, archive it, and submit to App Store Connect, just like any iOS app. The shared framework is bundled in.
There’s no special “KMP store” — users download ordinary native apps; KMP is invisible to them.
CI/CD
Your pipeline runs the shared commonTest suite once, then builds each platform app. Catching logic bugs in shared tests means you fix them for both platforms simultaneously.
The big payoff
By sharing logic, you remove duplicated code and the bugs that come from two diverging implementations — while each app stays fully native to its users. That balance is exactly why KMP has grown so popular.
Common mistakes
- Not writing shared tests — you lose one of KMP’s biggest advantages.
- Treating KMP publishing as special — it’s just two normal app submissions.
- Skipping interfaces/DI, which makes the shared code hard to test.
Summary: Write tests once in commonTest to cover the code both apps share, lean on the KMP ecosystem (Ktor, SQLDelight, Koin, SKIE), and publish two ordinary native apps to the Play Store and App Store. Shared logic + native apps is the KMP payoff.