Limitations
Supported types
✅ In general, Mokkery is able to mock a type that is fully overridable. That includes:
- 🧩 Interfaces
- ➡️ Functional types
- 🏛️ Final classes with all-open plugin
- 🏗️ Abstract/open classes with public constructor and all overridable public members.
* It's possible to allow final or inline members
❌ Things that Mokkery is unable to mock:
- ➡️ Functions (extensions included)
- 🏛️ Final classes that are already compiled (it's not possible to apply
all-open
plugin) - 🔢 Primitives
- 🔐 Sealed types
- 🗽 Objects
Value classes (WASM)
Mokkery supports mocking methods involving value classes, whether they serve as return types or parameters.
However, for WASM, this support is restricted only to value classes originating from the standard library
(kotlin.Result
and kotlin.time.Duration
).
Any other value class requires registering AutofillProvider
that returns some empty value:
AutofillProvider.forInternals.types.register { ValueClass(null) }
Calling mock
& spy
Type passed to spy
and mock
must be directly specified. Following code is illegal:
inline fun <reified T : Any> myMock() = mock<T>()
However, it is not completely forbidden to use generic parameters. Following code is allowed:
fun <T : Any> myListMock() = mock<List<T>>()
Calling every
& verify
To ensure that every
and verify
work as expected, compiler plugin transforms the code inside their blocks. This
transformation currently restricts those blocks from extracting their parts into separate functions. It also dictates that block
parameter must always be a lambda expression (not function reference nor lambda assigned to a variable). Following code is illegal:
@Test
fun test() {
// ...
verify {
foo()
}
}
private fun ArgMatchersScope.foo() {
repository.findAll()
}
However, it is perfectly fine to extract whole verify
or every
call to separate function:
@Test
fun test() {
// ...
foo()
}
private fun foo() {
verify {
repository.findAll()
}
}
Using matchers
All matchers
The biggest limitation is that you must not assign matchers to variables. Following code is illegal:
everySuspend {
val matcher = any<Int>()
reporitory.findById(matcher)
} returns Book(...)
Composite matchers
When using composite matchers (whenever matcher accepts other matcher like logical matchers), you cannot use literals. Code below is illegal:
everySuspend { repository.findById(or("1", "2")) } returns Book(...)
You must use eq
matcher explicitly:
everySuspend { repository.findById(or(eq("1"), eq("2"))) } returns Book(...)
Varargs matchers
If you pass varargs as array, it might sometimes lead to ambiguity. Calls presented below are prohibited:
everySuspend { repository.findAllById(ids = arrayOf("1", *anyVarargs(), "3")) } returns emptyList()
everySuspend { repository.findAllById(ids = arrayOf("1", any())) } returns emptyList()
While passing varargs as arrays make sure that you don't mix matchers with literals. Calls presented below are allowed:
everySuspend { repository.findAllById(ids = arrayOf(eq("1"), *anyVarargs(), eq("3"))) } returns emptyList()
everySuspend { repository.findAllById(ids = arrayOf(eq("1"), any())) } returns emptyList()