
Compiler-plugin mocking that generates compile-time stubs with an expressive DSL, argument matchers, coroutine support, final-class mocking and zero runtime reflection for type-safe testing.
A lightweight mocking framework for Kotlin Multiplatform. Stub generates mock implementations at compile time using a Kotlin compiler plugin — no reflection, no manual mock classes. Works on JVM, Android, iOS, and JS.
| API | Description |
|---|---|
stub<T>() |
Create a stub for any interface or final class |
every { } returns |
Configure a return value |
every { } throws |
Configure an exception |
every { } answers { } |
Compute a return value dynamically |
verify { } |
Assert a method was called |
any() |
Match any argument |
eq(value) |
Match by equality |
coEvery { } |
every for suspend functions |
coVerify { } |
verify for suspend functions |
import org.yarokovisty.stub.dsl.*
import kotlin.test.Test
import kotlin.test.assertEquals
interface UserRepository {
fun findById(id: Int): String
}
class UserRepositoryTest {
private val repository: UserRepository = stub()
@Test
fun returnsConfiguredValue() {
every { repository.findById(1) } returns "Alice"
assertEquals("Alice", repository.findById(1))
verify { repository.findById(1) }
}
}// Match any arguments
every { repository.findById(any()) } returns "Unknown"
// Override specific cases — last registered wins
every { repository.findById(eq(1)) } returns "Alice"
repository.findById(1) // "Alice"
repository.findById(999) // "Unknown"No open keyword needed — the compiler plugin handles it:
class DataSource {
fun load(): String = "real"
}
val dataSource: DataSource = stub()
every { dataSource.load() } returns "mocked"import kotlinx.coroutines.test.runTest
interface ApiService {
suspend fun fetchData(): String
}
@Test
fun testSuspend() = runTest {
val api: ApiService = stub()
coEvery { api.fetchData() } returns "async result"
assertEquals("async result", api.fetchData())
coVerify { api.fetchData() }
}clearStubs(repository) // Clear answers and call history
clearInvocations(repository) // Clear call history onlyApply the compiler plugin and add the DSL dependency:
build.gradle.kts
plugins {
id("io.github.yarokovisty.stub.compiler") version "<version>"
}
kotlin {
sourceSets {
commonTest.dependencies {
implementation("io.github.yarokovisty:stub-dsl:<version>")
implementation("io.github.yarokovisty:stub-runtime:<version>")
implementation(libs.kotlin.test)
implementation(libs.kotlinx.coroutines.test) // for coEvery/coVerify
}
}
}JVM, Android, iOS (iosArm64, iosSimulatorArm64, iosX64), JS (Node.js)
| Dependency | Version |
|---|---|
| Kotlin | 2.2.20+ |
| Gradle | 8.14+ |
Copyright (c) YarokovistY. All rights reserved.
A lightweight mocking framework for Kotlin Multiplatform. Stub generates mock implementations at compile time using a Kotlin compiler plugin — no reflection, no manual mock classes. Works on JVM, Android, iOS, and JS.
| API | Description |
|---|---|
stub<T>() |
Create a stub for any interface or final class |
every { } returns |
Configure a return value |
every { } throws |
Configure an exception |
every { } answers { } |
Compute a return value dynamically |
verify { } |
Assert a method was called |
any() |
Match any argument |
eq(value) |
Match by equality |
coEvery { } |
every for suspend functions |
coVerify { } |
verify for suspend functions |
import org.yarokovisty.stub.dsl.*
import kotlin.test.Test
import kotlin.test.assertEquals
interface UserRepository {
fun findById(id: Int): String
}
class UserRepositoryTest {
private val repository: UserRepository = stub()
@Test
fun returnsConfiguredValue() {
every { repository.findById(1) } returns "Alice"
assertEquals("Alice", repository.findById(1))
verify { repository.findById(1) }
}
}// Match any arguments
every { repository.findById(any()) } returns "Unknown"
// Override specific cases — last registered wins
every { repository.findById(eq(1)) } returns "Alice"
repository.findById(1) // "Alice"
repository.findById(999) // "Unknown"No open keyword needed — the compiler plugin handles it:
class DataSource {
fun load(): String = "real"
}
val dataSource: DataSource = stub()
every { dataSource.load() } returns "mocked"import kotlinx.coroutines.test.runTest
interface ApiService {
suspend fun fetchData(): String
}
@Test
fun testSuspend() = runTest {
val api: ApiService = stub()
coEvery { api.fetchData() } returns "async result"
assertEquals("async result", api.fetchData())
coVerify { api.fetchData() }
}clearStubs(repository) // Clear answers and call history
clearInvocations(repository) // Clear call history onlyApply the compiler plugin and add the DSL dependency:
build.gradle.kts
plugins {
id("io.github.yarokovisty.stub.compiler") version "<version>"
}
kotlin {
sourceSets {
commonTest.dependencies {
implementation("io.github.yarokovisty:stub-dsl:<version>")
implementation("io.github.yarokovisty:stub-runtime:<version>")
implementation(libs.kotlin.test)
implementation(libs.kotlinx.coroutines.test) // for coEvery/coVerify
}
}
}JVM, Android, iOS (iosArm64, iosSimulatorArm64, iosX64), JS (Node.js)
| Dependency | Version |
|---|---|
| Kotlin | 2.2.20+ |
| Gradle | 8.14+ |
Copyright (c) YarokovistY. All rights reserved.