Compile-time mocks and fakes for Kotlin Multiplatform tests — generated by a KSP processor, not by reflection.
MocKMP turns a plain interface or abstract class into a mock or a fake for your tests.
You ask for what a test needs with an annotation — @Mock, @Fake, @UsesMocks, @UsesFakes — and a
KSP processor generates the implementation, ready to inject.
class MyTest : TestsWithMocks() {
override fun setUpMocks() = mocker.injectMocks(this)
@Mock lateinit var view: View
@Fake lateinit var model: Model
val controller by withMocks { Controller(view = view, firstModel = model) }
@Test fun controllerTest() {
every { view.render(isAny()) } returns true
controller.start()
verify { view.render(model) }
}
}No reflection, no dynamic proxies, no "relaxed" mode papering over a call nobody mocked. An interface, a generated implementation, and a compiler that rejects a mock or a fake for a type that can’t be one.
Compile-time, not reflection. A KSP processor generates a real class implementing the interface or abstract class you asked to mock or fake, so it behaves identically on every target — including the ones with no runtime reflection at all, like iOS, JS and Wasm.
Mocking and faking answer different questions. A mock's behaviour is defined per test, and every
call on it can be verified; a fake's data is inert and zero-valued, and nothing about it is
checked. Reach for a fake when a collaborator only needs to exist, and a mock when the test needs to
configure or verify it.
Nothing is generated until you ask for it. @UsesMocks / @UsesFakes — or a @Mock / @Fake
property — requests exactly the types a given test needs, so an interface used across a large
codebase doesn’t grow generated code everywhere it’s declared, only where it’s actually mocked or
faked.
Injection kills the constructor boilerplate. Annotate properties @Mock or @Fake and call
mocker.injectMocks(this); inherited properties are injected too, so a shared base test class works
exactly as if its mocks had been declared locally.
The TestsWithMocks helper collapses the ceremony further. Inherit it and get a Mocker, an
automatic reset before every test, withMocks property delegates rebuilt fresh each time, and
every / everySuspending / verify / verifyWithSuspend callable without the mocker. prefix.
Constraints read the same in a definition and in a verification. isAny, isEqual, isNotNull,
isInstanceOf, and any custom constraint you write with isValid, work identically whether they
appear inside every or inside verify — one matcher vocabulary, not two.
Multiplatform, with no platform-specific surprises. mockmp-runtime targets every platform MocKMP
supports and behaves the same on each of them.
|
Warning
|
Version 2.0 brings compatibility with Kotlin 2.0, but with breaking changes. If you’re on version 1.17, see the 1.x to 2.x migration guide. |
|
Warning
|
Version 3.0 brings compatibility with AGP 9, but becomes incompatible with AGP 8 or earlier. Only update to MocKMP 3.0 if you are also updating to AGP 9 — if you’re on version 2.1, see the 2.x to 3.x migration guide. |
Apply the Gradle plugin to your Kotlin/Multiplatform module, then enable it on the test source sets you want mocks and fakes generated for:
plugins {
kotlin("multiplatform")
id("com.google.devtools.ksp") // (1)
id("org.kodein.mock.mockmp") version "{version}" // (2)
}
kotlin {
// Your Kotlin/Multiplatform configuration
}
mockmp { // (3)
onTest {
withHelper() // or withHelper(junit5)
}
}-
KSP hosts the MocKMP processor.
-
The MocKMP Gradle plugin — it wires the runtime and the processor for you, so there is no dependency to add by hand.
-
Configured after the
kotlin { }block, so the plugin can see your targets.withHelper()also pulls in theTestsWithMockshelper class.
The plugin applies just as well to a single-target kotlin("jvm") or kotlin("android") project.
See MocKMP Documentation.