You have a mock with a suspend function and you write every { repo.load() } returns data — it won't compile. Why, and what do you use instead?
answer
- every lambda is not suspend
- coEvery for suspend stubs
- coVerify mirrors verify
- tail (returns/throws) is identical
- wrap calls in runTest
basics
~10 severy can only call ordinary functions. A suspend function must be called from a coroutine, so MockK gives you coEvery, which can run suspend calls inside its stub block. Use coEvery for suspend functions.
solid answer
~40 sMockK's every { } lambda is a normal (non-suspend) lambda, so you can't invoke a suspend function inside it — the compiler rejects the call because suspend functions require a coroutine/suspend context. MockK provides coEvery { } whose lambda is itself suspend, so calling repo.load() (a suspend fun) inside it compiles and records the stub. The matching verification is coVerify { } (vs verify { }). The chained part after the block — returns, throws, answers — is identical to every; only the block needs to be suspend-capable. Rule of thumb: same function for stubbing, but co-prefixed (coEvery, coVerify, coAnswers) whenever the mocked function is declared with suspend.
code
kotlin · 7 linesval repo = mockk<UserRepo>()
coEvery { repo.load(1) } returns User("Ann")
@Test fun t() = runTest {
assertEquals("Ann", repo.load(1).name)
coVerify { repo.load(1) }
}go deeper
Knows that suspend functions need coEvery instead of every and that the call must happen in a coroutine.
Explains the suspend-lambda compiler constraint and pairs coEvery with coVerify, using runTest for the call site.
Articulates why the API is split rather than overloaded and can mix every/coEvery cleanly on one mock.
Frames the co-prefixed API as a deliberate, opt-in coroutine boundary marker and reasons about how it composes with structured-concurrency test scaffolding.
## The core problem A function declared with the `suspend` keyword can only be called from another `suspend` function or from a coroutine builder (`launch`, `async`, `runTest`, etc.). The compiler enforces this. MockK's `every { ... }` takes a **plain lambda** (not suspend). So inside that lambda you cannot call a `suspend` function — the compiler errors with something like *"Suspend function 'load' should be called only from a coroutine or another suspend function."* ## The fix: the co-prefixed API MockK ships **suspend-aware twins** for exactly this case: - `coEvery { }` — stub a suspend function (the lambda is `suspend`). - `coVerify { }` — verify a suspend function was called. - `coAnswers { }` — provide a dynamic suspend answer. Everything *after* the block is shared with the non-co API: `returns`, `returnsMany`, `throws`, `answers`. ```kotlin interface UserRepo { suspend fun load(id: Long): User } val repo = mockk<UserRepo>() // WRONG — won't compile, load() is suspend // every { repo.load(1) } returns User("Ann") // RIGHT coEvery { repo.load(1) } returns User("Ann") @Test fun loads() = runTest { val u = repo.load(1) // call from a coroutine assertEquals("Ann", u.name) coVerify { repo.load(1) } // suspend-aware verify } ``` ## Why not just make `every` suspend? `every` is used for the vast majority of non-suspend stubs; keeping its lambda non-suspend keeps the common case simple. The co-variants are opt-in and signal at the call site that you're dealing with a coroutine boundary. ## Key takeaways - `suspend` collaborator ⇒ use the `co`-prefixed function. - The tail (`returns`, `throws`, `answers`) is unchanged. - Run the test body inside `runTest` so you actually have a coroutine to call the mock from.
- If a class has both suspend and non-suspend functions, can you mix every and coEvery on the same mock?Yes. Use every for the plain functions and coEvery for the suspend ones; they target the same mock object independently.
- Does coEvery require any extra MockK dependency?No. coEvery/coVerify/coAnswers are part of core MockK; you only need a coroutines test runner like kotlinx-coroutines-test for runTest.
every is a phone that only does voice; coEvery is the same phone that also handles video calls — same dialing, extra capability.
saying these in an interview costs you the question
- Claiming every works for suspend functions if you add a return type
- Saying you must wrap the stub body in launch instead of using coEvery
- Thinking coEvery needs a separate MockK artifact
- Believing returns/throws differ between every and coEvery