Skip to main content

Answers

Essentials

To define a const answer, use returns:

every { mock.getAt(index = any()) } returns 100

To throw an exception, use throws:

every { mock.getAt(index = any()) } throws IllegalArgumentException()

To provide more complex answer, use calls:

  • For regular functions:
every { mock.getAt(index = any()) } calls { (index: Int) -> index + 1 }
  • For suspend functions:
everySuspend { mock.fetchAt(index = any()) } calls { (index: Int) ->
delay(1_000) // suspension is allowed here!
index + 1
}

The calls lambda provides CallArgs instance as it and one of two CallDefinitionScope variants: BlockingCallDefinitionScope for every or SuspendCallDefinitionScope for everySuspend.

Utilities

To return specific arg, use returnsArgAt:

every { mock.getAt(index = any()) } returnsArgAt 0

mock.getAt(10) // returns 10 that was passed as an argument

If you need a more complex answer for functions that return Result, use callsCatching :

every { mock.getAtCatching(any()) } callsCatching { (index: Int) ->
if (index < 0) error("Negative index not allowed!")
index + 1
}
mock.getAtCatching(-1) // returns failed Result
mock.getAtCatching(2) // returns successful Result

To return Result.success from functions that return Result, use returnsSuccess:

every { mock.getAtCatching(index = 0) } returnsSuccess 1

mock.getAtCatching(0) // returns successful Result with 1

To return Result.failure from functions that return Result, use returnsFailure:

every { mock.getAtCatching(index = 30) } returnsFailure IndexOutOfBoundsException()

mock.getAtCatching(30) // returns failed Result with IndexOutOfBoundsException

To return a value provided each time by a function, use returnsBy:

private var number = 1

// ...

every { mock.getAt(any()) } returnsBy ::number

mock.getAt(0) // returns 1 provided by `number`
number = 3
mock.getAt(0) // returns 3 provided by updated `number`
tip

For functions returning a Result, you can use returnsSuccessBy or returnsFailureBy.

To throw an exception provided each time by a function, use throwsBy:

every { mock.getAt(any()) } throwsBy ::IllegalStateException

runCatching { mock.getAt(0) } // throws newly created IllegalStateException
runCatching { mock.getAt(0) } // throws newly created IllegalStateException

To throw IllegalStateException with specific message (just like kotlin.error), use throwsErrorWith:

every { mock.getAt(any()) } throwsErrorWith "Failed!"

Sequence of answers

You can define a sequence of answers using sequentially:

every { mock.getAt(any()) } sequentially {
returns(0)
calls { 1 }
throws(IllegalStateException())
}
mock.getAt(0) // returns 0
mock.getAt(1) // returns 1
runCatching { mock.getAt(2) } // throws IllegalStateException
mock.getAt(3) // fails - no more answers

At the end of sequentially block you can repeat a sequence of answers with repeat:

every { mock.getAt(any()) } sequentially {
returns(0)
repeat { returns(1) }
}
mock.getAt(0) // returns 0
mock.getAt(1) // returns 1
mock.getAt(2) // returns 1
mock.getAt(3) // returns 1

You can use sequentiallyRepeat as a shorthand if you want to define repeating sequence:

every { mock.getAt(any()) } sequentiallyRepeat {
returns(0)
returns(1)
}
mock.getAt(0) // returns 0
mock.getAt(1) // returns 1
mock.getAt(2) // returns 0
mock.getAt(3) // returns 1

You can use sequentiallyReturns and sequentiallyThrows as a shorthand:

every { mock.getAt(any()) } sequentiallyReturns listOf(0, 1)
mock.getAt(0) // returns 0
mock.getAt(1) // returns 1
mock.getAt(2) // fails - no more answers

You can nest sequentially calls:

every { mock.getAt(any()) } sequentially {
returns(0)
sequentially {
returns(1)
returns(2)
}
returns(3)
}
mock.getAt(0) // returns 0
mock.getAt(1) // returns 1
mock.getAt(2) // returns 2
mock.getAt(3) // returns 3
mock.getAt(4) // fails - no more answers

Calling original implementation

The most straightforward way to call original function is to use calls overload:

every { mock.getAt(any()) } calls original

mock.getAt(2) // this calls original function implementation with 2

You can pass different arguments to original call:

every { mock.getAt(any()) } calls originalWith(3)

mock.getAt(2) // this calls original function implementation with 3
info

If mocked type is an interface, the default implementation is called.

Resolving ambiguity

While using multiple types mocking usage of original might not be possible, because there are multiple super calls available for single function. Instead of original use superOf<T> with supertype specified.

val mock = mockMany<A, B> {
every { t1.sharedFunction(any()) } calls superOf<A>()
}
mock.t1.sharedFunction(2) // this calls function implementation from A with 2

You can pass different arguments to super call:

val mock = mockMany<A, B> {
every { t1.sharedFunction(any()) } calls superWith<A>(3)
}
mock.t1.sharedFunction(2) // this calls function implementation from A with 3

Super calls API in calls

All of those features are accessible from calls scope:

every { mock.getAt(any()) } calls {
callOriginal()
callOriginalWith(3)
callSuper(BaseFoo::class)
callSuperWith(BaseFoo::class, 3)
}

Calling spied implementation

When working with spies, you may want to call the real implementation while adding some extra behavior. This can be done using callSpied from calls:

every { spy.getAt(any()) } calls {
// ...
callSpied()
}

If you need to override the arguments passed to the spied function, use callSpiedWith:

every { spy.getAt(any()) } calls {
// ...
callSpiedWith(3)
}

Extending answers API

The answers API provides a way to define custom behavior for mocked function calls in Mokkery. It is built around two core interfaces:

@DelicateMokkeryApi
public interface Answer<out T> {

public fun call(scope: MokkeryBlockingCallScope): T

public suspend fun call(scope: MokkerySuspendCallScope): T
}

// ...

public interface AnsweringScope<T> {

@DelicateMokkeryApi
public infix fun answers(answer: Answer<T>)
}

Core concepts

The Answer interface represents custom behavior for mocked calls. It has two call overloads:

  • call(MokkeryBlockingCallScope) – used for regular (blocking) functions.
  • call(MokkerySuspendCallScope) – used for suspend functions.

The AnsweringScope interface provides the answers function, which registers an Answer for a particular call.

Some custom answers may work with both regular and suspend functions, while others support only one type. However, AnsweringScope itself does not enforce any restrictions - you can technically register any Answer for any call.

This flexibility can lead to misuse, such as registering a suspend-only answer for a blocking call. For this reason, both AnsweringScope.answers and the Answer interface are marked as delicate APIs.

Restricting usage

To provide compile-time safety, Mokkery defines two subtypes of AnsweringScope:

public interface SuspendAnsweringScope<T> : AnsweringScope<T>

public interface BlockingAnsweringScope<T> : AnsweringScope<T>

These are marker interfaces - they don’t add extra functions but indicate whether the context is for a regular function (BlockingAnsweringScope), or a suspend function (SuspendAnsweringScope).

Mokkery uses them as follows:

  • every returns a BlockingAnsweringScope
  • everySuspend returns a SuspendAnsweringScope

Custom Answer implementations should not be used directly. Instead, expose them through convenience extensions on the appropriate scope type.

Example: a suspend-only answer that delays before returning a value:

infix fun SuspendAnsweringScope<T>.returnsDelayed(value: T) {
answers(ReturnsDelayedAnswer(value))
}

// you can optionally mark this class as private
private class ReturnsDelayedAnswer<T>(private val value: T) : Answer<T> {
public fun call(scope: MokkeryBlockingCallScope): T = error("Not supported")

public suspend fun call(scope: MokkerySuspendCallScope): T {
delay(1_000)
return value
}
}

// Usage:
everySuspend { mock.fetchAt(any()) } returnsDelayed 10
// ✅ compiles - suspend context

every { mock.getAt(any()) } returnsDelayed 10
// ❌ does NOT compile - regular context

Some answers are valid for both regular and suspend functions. For consistency, you should still declare an extension function, but this time use AnsweringScope as the receiver:

infix fun AnsweringScope<T>.returns(value: T) {
answers(ReturnsAnswer(value))
}

private class ReturnsAnswer<T>(private val value: T) : Answer<T> {
public fun call(scope: MokkeryBlockingCallScope): T = value
public suspend fun call(scope: MokkerySuspendCallScope): T = value
}

// Usage:
everySuspend { mock.fetchAt(any()) } returns 10 // suspend
every { mock.getAt(any()) } returns 10 // regular
// ✅ both compile

Using existing answers

If your custom answer can be expressed using other built-in answers, you don’t need to create a new Answer implementation. Instead, declare an extension using existing answers:

fun <T> SuspendAnsweringScope<T>.returnsDelayed(value: T) {
calls {
delay(1_000)
value
}
}

This is simpler and avoids extra boilerplate.

Answer description

The Answer interface lets you implement a description() function, which provides a human-readable explanation of the answer. This is especially useful for debugging, e.g., with printMokkeryDebug

The description should resemble the code usage:

infix fun SuspendAnsweringScope<T>.returnsDelayed(value: T) {
answers(ReturnsDelayedAnswer(value))
}

// ...
private class ReturnsDelayedAnswer<T>(private val value: T) : Answer<T> {
// ...
override fun description() = "returnsDelayed $value"
}

Answer implementation helpers

When implementing custom answers, these helper interfaces can useful:

  • Answer.Suspending - For suspend-only answers. Provides a default blocking implementation that throws an exception.
  • Answer.Blocking - For blocking-only answers. Provides a default suspend implementation that throws an exception.
  • Answer.Unified - Adds a third call overload with MokkeryCallScope. The other two overloads delegate to this function, so you only need to implement one function. Useful when the same logic applies to both blocking and suspend contexts.