Quick start
Please read limitations section!
Mocking
To create a mock of given type, use mock function:
val foo = mock<Foo>()
If you call a member function that has no defined behavior, it will result in runtime error by default. To learn how to change this locally or globally read mock mode section.
To define an answer for regular member function, use every:
every { foo.getAll() } returns listOf(1, 2, 3)
For property, call getter or setter inside every:
// getter
every { foo.values } returns listOf(1, 2, 3)
// setter
every { foo.values = any() } returns Unit
For suspending member function, use everySuspend:
everySuspend { foo.fetchAll() } returns listOf(1, 2, 3)
every and everySuspend can be used with function references as a shorthand:
every(foo::getAll) returns listOf(1, 2)
every(foo::values::get) returns listOf(2, 3)
every(foo::values::set) returns Unit
everySuspend(foo::fetchAt) returns 10
foo.getAll() // returns listOf(1, 2)
foo.values // returns listOf(2, 3)
foo.values = emptyList() // returns Unit
foo.fetchAt(0) // returns 10
foo.fetchAt(1) // returns 10
foo.fetchAt(2) // returns 10
Make sure that you are calling a member function of a mock type! Mocking extension functions is not supported!
It's worth to notice that everySuspend is not suspending function, so it's possible to configure suspending functions in non-suspending context e.g. test class property.
You can move your behavior config to mock block:
val mock = mock<Foo>(autoUnit) {
every { getAll() } returns listOf(1, 2, 3)
everySuspend { fetchAll() } returns listOf(1, 2, 3)
}
returns is quite simple and returns always the same value. If you want to discover other behaviors, check answers guide!
If a member function accepts parameters, you can define an answer only for specific parameters:
every { foo.getAt(0) } returns 1
every { foo.getAt(1) } returns 2
foo.getAt(0) // returns 1
foo.getAt(1) // returns 2
foo.getAt(2) // error - answer not defined
To accept more broad range of parameter values, use matchers:
every { foo.getAt(any()) } returns 0
foo.getAt(0) // returns 0
foo.getAt(1) // returns 0
foo.getAt(2) // returns 0
When multiple answers match a call, the one defined later takes precedence.
For member function with extension parameter, you need to use special ext function:
import dev.mokkery.templating.ext
// ...
every { foo.ext { any<String>().toNumber() } } returns 10
foo.run { "10".toNumber() } // returns 10
For member function with context parameters, you need to use special ctx function:
import dev.mokkery.templating.ctx
// ...
every { ctx(any<FooContext>()) { foo.getAllWithContext() } } returns listOf(1, 2, 3)
context(FooContext()) {
foo.getAllWithContext() // returns listOf(1, 2, 3)
}
ext and ctx behave like standard Kotlin scope functions, but they must be used exclusively!
Verifying
To verify that some calls occurred use verify:
verify {
foo.getAll()
}
If you want to verify suspending functions use verifySuspend:
verifySuspend {
foo.fetchAll()
}
Each verification is performed on unverified calls. In result, repeated verifications may give different results:
foo.getAt(1)
verify { foo.getAt(1) } // ✅
verify { foo.getAt(1) } // ❌ - no matching calls
By default, verification works in soft mode. It checks if each call pattern occurred at least once.
In this mode, each check is performed independently so in example below, both checks have the same result:
foo.getAll()
foo.getAll()
verify {
foo.getAll()
// ✅ - `getAll` was called at least once
}
foo.getAll()
foo.getAll()
verify {
foo.getAll()
foo.getAll()
// ✅ - `getAll` was called at least once
// the only difference is that `getAll` check is duplicated
}
In conclusion, there is no point of putting duplicated patterns in verify with soft mode.
Read verifying section to learn about more strict verification modes and how to configure them locally and globally!