Quick start
Let's assume we have given interface:
interface BooksRepository {
suspend fun findById(id: String): Book
suspend fun countAll(): Int
fun findAll(): Flow<Book>
}
Please read limitations section!
Mocking
To create a mock of BooksRepository
use mock
function:
val repository = mock<BooksRepository>()
If you call a method that has no defined behaviour, 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 function use every
:
every { repository.findAll() } returns flowOf(Book(...))
For suspending function use everySuspend
:
everySuspend { repository.countAll() } returns 1
Make sure that you are calling a method 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 behaviour config to mock
block:
val repository = mock<BookRepository>(autoUnit) {
every { findAll() } returns flowOf(Book(...))
everySuspend { countAll() } returns 1
}
returns
is quite simple and returns always the same value. If you want to discover other behaviours check answers guide!
If a method accepts parameters, you can define an answer only for specific parameters:
everySuspend { repository.findById("1") } returns Book(id = "1", ...)
everySuspend { repository.findById("2") } returns Book(id = "1", ...)
repository.findById("1") // returns Book(id = "1", ...)
repository.findById("2") // returns Book(id = "2", ...)
repository.findById("3") // error - answer not defined
To accept more broad range of parameter values use matchers:
everySuspend { repository.findById(any()) } returns Book(id = "1", ...)
repository.findById("1") // returns Book(id = "1", ...)
repository.findById("2") // returns Book(id = "1", ...)
repository.findById("3") // returns Book(id = "1", ...)
When multiple answers match a call, the one defined later takes precedence.
Verifying
To verify that some calls occured use verify
:
verify {
repository.findAll()
}
If you want to verify suspending functions use verifySuspend
:
verifySuspend {
repository.countAll()
}
Each verification is performed on unverified calls. In result, repeated verifications may give different results:
repository.findById("1")
verify { repository.findById("1") } // succeeds
verify { repository.findById("1") } // fails - no matching calls
By default, verify
works in soft mode. It checks if each call pattern occurred at least once.
In this mode, each verification is performed independently so in example below, both verifications have the same result:
repository.findAll()
repository.findAll()
// verification passes, because findAll was called at least once
verify {
repository.findAll()
}
repository.findAll()
repository.findAll()
// verification passes, because findAll was called at least once
// the only difference is that `findAll` check is duplicated
verify {
repository.findAll()
repository.findAll()
}
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!