Comprehensive mocking library for Kotlin with native coroutine support and advanced DSL features.
—
Behavior definition system for specifying how mocks should respond to method calls, with comprehensive support for return values, exceptions, custom answers, and coroutine operations.
Core stubbing functions for defining mock behavior.
/**
* Starts a stubbing block for defining mock behavior
* @param stubBlock Block containing the method call to stub
* @return MockKStubScope for specifying the response
*/
fun <T> every(stubBlock: MockKMatcherScope.() -> T): MockKStubScope<T, T>
/**
* Coroutine version of every for suspend functions
* @param stubBlock Block containing the suspend method call to stub
* @return MockKStubScope for specifying the response
*/
fun <T> coEvery(stubBlock: suspend MockKMatcherScope.() -> T): MockKStubScope<T, T>
/**
* Shortcut for stubbing Unit-returning functions
* @param stubBlock Block containing the Unit method call to stub
*/
fun justRun(stubBlock: MockKMatcherScope.() -> Unit)
/**
* Coroutine version of justRun for suspend Unit functions
* @param stubBlock Block containing the suspend Unit method call to stub
*/
fun coJustRun(stubBlock: suspend MockKMatcherScope.() -> Unit)Usage Examples:
val userService = mockk<UserService>()
// Basic return value stubbing
every { userService.getUserById("123") } returns User("123", "John")
// Coroutine stubbing
every { userService.getUserByIdAsync("123") } returns User("123", "John")
// Unit function stubbing
justRun { userService.deleteUser("123") }
// Suspend unit function stubbing
coJustRun { userService.deleteUserAsync("123") }Different ways to specify how stubbed methods should respond.
interface MockKStubScope<T, B> {
/** Returns a constant value */
infix fun returns(returnValue: T): MockKAdditionalAnswerScope<T, B>
/** Returns different values in sequence */
infix fun returnsMany(values: List<T>): MockKAdditionalAnswerScope<T, B>
/** Returns the nth argument passed to the method */
infix fun returnsArgument(n: Int): MockKAdditionalAnswerScope<T, B>
/** Throws an exception */
infix fun throws(ex: Throwable): MockKAdditionalAnswerScope<T, B>
/** Throws different exceptions in sequence */
infix fun throwsMany(exList: List<Throwable>): MockKAdditionalAnswerScope<T, B>
/** Provides a custom answer implementation */
infix fun answers(answer: Answer<T>): MockKAdditionalAnswerScope<T, B>
/** Provides a lambda-based answer */
infix fun answers(answer: MockKAnswerScope<T, B>.(Call) -> T): MockKAdditionalAnswerScope<T, B>
/** Provides a coroutine-based answer */
infix fun coAnswers(answer: suspend MockKAnswerScope<T, B>.(Call) -> T): MockKAdditionalAnswerScope<T, B>
}Usage Examples:
val userService = mockk<UserService>()
// Return constant value
every { userService.getUserById(any()) } returns User("123", "John")
// Return sequence of values
every { userService.getNextId() } returnsMany listOf("1", "2", "3")
// Return argument
every { userService.echoId(any()) } returnsArgument 0
// Throw exception
every { userService.getUserById("invalid") } throws UserNotFoundException()
// Throw sequence of exceptions
every { userService.unstableOperation() } throwsMany listOf(
NetworkException(),
TimeoutException()
)
// Custom answer with call information
every { userService.processUser(any()) } answers {
val user = firstArg<User>()
User(user.id, user.name.uppercase())
}
// Coroutine answer
coEvery { userService.processUserAsync(any()) } coAnswers {
delay(100)
val user = firstArg<User>()
User(user.id, user.name.uppercase())
}Access to call information within custom answers.
abstract class MockKAnswerScope<T, B> {
/** Current call information */
val call: Call
/** Arguments passed to the method */
val args: List<Any?>
/** Number of arguments */
val nArgs: Int
/** Mock object being called */
val self: Any
/** Method being called */
val method: MethodDescription
/** Access to first argument with type casting */
fun <T> firstArg(): T
/** Access to second argument with type casting */
fun <T> secondArg(): T
/** Access to third argument with type casting */
fun <T> thirdArg(): T
/** Access to last argument with type casting */
fun <T> lastArg(): T
/** Access to nth argument with type casting */
fun <T> arg(n: Int): T
/** For spies - calls the original implementation */
fun callOriginal(): T
}Usage Examples:
val userService = spyk<UserService>()
// Access arguments in answer
every { userService.createUser(any(), any()) } answers {
val name = firstArg<String>()
val email = secondArg<String>()
User(generateId(), name, email)
}
// Call original implementation (for spies)
every { userService.validateUser(any()) } answers {
val user = firstArg<User>()
if (user.id == "test") {
true // Custom behavior for test user
} else {
callOriginal() // Use real implementation
}
}
// Access call metadata
every { userService.logOperation(any()) } answers {
val operation = firstArg<String>()
logger.info("Mock ${method.name} called with: $operation")
callOriginal()
}Pre-built answer implementations for common scenarios.
object Runs
object Awaits
// Used with 'just' infix function
infix fun MockKStubScope<Unit, *>.just(runs: Runs)
infix fun MockKStubScope<Unit, *>.just(awaits: Awaits)Usage Examples:
// Equivalent to justRun
every { userService.deleteUser(any()) } just Runs
// For suspend functions that never return
coEvery { userService.waitForever() } just AwaitsCapturing arguments during stubbing for later inspection.
/**
* Creates a capturing slot for single values
*/
inline fun <reified T : Any?> slot(): CapturingSlot<T>
class CapturingSlot<T> {
val captured: T
val isCaptured: Boolean
val isNull: Boolean
fun clear()
}Usage Examples:
val userService = mockk<UserService>()
val userSlot = slot<User>()
val idSlot = slot<String>()
// Capture argument during stubbing
every { userService.saveUser(capture(userSlot)) } returns "user-id"
every { userService.getUserById(capture(idSlot)) } returns User("123", "John")
// Use the mock
userService.saveUser(User("123", "John"))
userService.getUserById("123")
// Access captured values
val capturedUser = userSlot.captured // User("123", "John")
val capturedId = idSlot.captured // "123"Stubbing property access on mocks.
interface MockKStubScope<T, B> {
/** Specify property type for proper stubbing */
fun <K> propertyType(): MockKStubScope<K, B>
/** Specify nullable property type */
fun <K> nullablePropertyType(): MockKStubScope<K?, B>
}Usage Examples:
val userService = mockk<UserService>()
// Property getter stubbing
every { userService.currentUser } returns User("123", "John")
// Property setter stubbing
every { userService.currentUser = any() } just Runs
// Property with type specification
every { userService.userCount } propertyType<Int>() returns 42Multiple stub configurations for the same method call.
interface MockKAdditionalAnswerScope<T, B> {
/** Add another answer that will be used in subsequent calls */
infix fun andThen(answer: T): MockKAdditionalAnswerScope<T, B>
/** Add another answer with different behavior */
infix fun andThenThrows(ex: Throwable): MockKAdditionalAnswerScope<T, B>
}Usage Examples:
val userService = mockk<UserService>()
// Chain different responses
every { userService.getUser() } returns User("1", "John") andThen User("2", "Jane")
// Mix returns and exceptions
every { userService.unstableOperation() } returns "success" andThenThrows NetworkException()
// Complex chaining
every { userService.getData() } returns "data1" andThen "data2" andThenThrows TimeoutException()Install with Tessl CLI
npx tessl i tessl/maven-io-mockk--mockk