skip to content

Relaxed Mocks & Spies

A relaxed mock auto-stubs everything so you only specify what matters, while a spy wraps a real object and calls through unless you override a member. Interviewers ask when each is appropriate, since both can hide missing expectations.

part ofKotlinoverview, primer and where to startread it →
on this pageshow

questions

5

In MockK, what does creating a mock with mockk<T>(relaxed = true) do, and how does it differ from a plain mockk<T>()?

level: juniorimportance: must knowfreq 70%

answer

  1. Strict = throws on unstubbed; relaxed = auto-default
  2. 0, false, "", empty collection
  3. Object returns -> nested relaxed mock
  4. relaxed = true reduces stubbing boilerplate
  5. Downside: hides unexpected calls

basics

~10 s

A relaxed mock auto-answers every call with a default value, so you don't have to stub each method. A plain mock throws if you call a method you never stubbed.

solid answer

~30 s

mockk<T>() is strict: calling any method that has no matching every { } stub throws MockKException ("no answer found"). mockk<T>(relaxed = true) is permissive: MockK auto-generates a default return for every unstubbed call — 0 for Int, false for Boolean, "" for String, empty collections, and a nested relaxed mock for arbitrary object return types. You still override specific calls with every { mock.foo() } returns ... when a test needs a real value. Relaxed mocks reduce boilerplate when you only care about a few methods, but they hide unexpected interactions, so prefer strict mocks plus explicit stubs when behavior matters.

code

kotlin · 10 lines
kotlin
val strict = mockk<UserRepo>()
// strict.count()  // throws MockKException: no answer found

val relaxed = mockk<UserRepo>(relaxed = true)
println(relaxed.count())        // 0  (auto default)
println(relaxed.findAll())      // [] (empty list)
val user = relaxed.findById(1)  // a nested relaxed mock<User>

every { relaxed.count() } returns 42
println(relaxed.count())        // 42 (override wins)

go deeper

for a junior

Knows relaxed = true avoids stubbing every method and returns sensible defaults.

for a middle

Lists the concrete default values and knows nested object returns become relaxed mocks; can still override with every.

for a senior

Articulates the trade-off (hidden interactions) and recommends strict-by-default, using relaxUnitFun as a middle ground.

for a principal

Sets team conventions on when relaxed is acceptable, weighing test brittleness vs. silent-default risk across a suite.

## What a mock is A **mock** is a stand-in object that records calls and returns whatever you tell it. In MockK you create one with `mockk<Type>()`. A **stub** is a programmed answer you attach with the `every { ... } returns ...` DSL. ## Strict mocks (the default) `mockk<Repo>()` is **strict**. If you call a method that has no matching `every` stub, MockK throws a `MockKException` like *"no answer found for: Repo(#1).find(...)"*. This forces you to be explicit about every interaction — good for catching surprises, verbose when you don't care. ## Relaxed mocks `mockk<Repo>(relaxed = true)` makes the mock **relaxed**: any unstubbed call returns an auto-generated default instead of throwing. Default values MockK picks: - Numbers → `0` / `0.0` - `Boolean` → `false` - `String` → `""` (empty string) - `Unit` → returns normally - Collections (`List`, `Set`, `Map`) → empty - Any other object type → a **new relaxed mock of that type** (recursively) - Nullable types → MockK returns a non-null relaxed default, not `null`, unless you stub `returns null`. You can still override individual methods: ```kotlin val repo = mockk<UserRepo>(relaxed = true) every { repo.count() } returns 5 // explicit val u = repo.findById(1) // unstubbed -> relaxed mock<User> println(repo.count()) // 5 ``` ## When to use which - **Strict + explicit stubs**: when the test asserts on specific return values or you want failures on unexpected calls. This is the recommended default. - **Relaxed**: when the collaborator has many methods but only a couple matter, or you mock something you only `verify` against and never read a return from. ## Caveat Relaxed mocks **hide bugs**: a typo'd or unexpected call silently returns `0`/`""` instead of failing loudly. Reach for `relaxUnitFun = true` (see other questions) when you only need void/`Unit` methods relaxed but want returning methods to stay strict.

  • What does a relaxed mock return for a method whose return type is a custom data class?
    A new relaxed mock instance of that data class type, generated recursively — not null and not a real constructed object.
  • Can you still stub a single method on a relaxed mock?
    Yes. every { } / returns overrides the auto default for that specific call; everything else stays relaxed.

A strict mock is a vending machine that errors unless you pre-load a slot; a relaxed mock dispenses a blank default for any button you press.

saying these in an interview costs you the question

  • Claiming a relaxed mock returns null by default (it returns a non-null relaxed default)
  • Saying a plain mockk() also auto-stubs returns (it throws instead)
  • Thinking relaxed disables verification — you can still verify { } calls
  • Believing relaxed makes the mock call real methods (that's spyk, not relaxed)

context

open as a page

What does spyk() create in MockK, and how does its behavior for unstubbed methods differ from a relaxed mock?

level: middleimportance: must knowfreq 60%

basics

~10 s

spyk() wraps a real object. Unstubbed methods run the real code and return real results. A relaxed mock never runs real code; unstubbed methods just return fake defaults.

open as a page

What is the difference between mockk(relaxed = true) and mockk(relaxUnitFun = true), and when would you choose relaxUnitFun?

level: middleimportance: should knowfreq 55%

basics

~10 s

relaxed = true auto-answers every method. relaxUnitFun = true only auto-answers methods that return Unit (void); methods that return a real value still throw unless you stub them.

open as a page

You're testing a service that depends on a collaborator with both void side-effect methods and value-returning methods. Walk through how you'd choose between strict mockk, relaxed = true, relaxUnitFun = true, and spyk, and the failure modes of each.

level: seniorimportance: should knowfreq 40%

basics

~20 s

Default to strict mockk and stub only what you read. Use relaxUnitFun for noisy void calls. Use relaxed only for collaborators you never read returns from. Use spyk when you want mostly real behavior with one method replaced.

open as a page

When using spyk in MockK, why can stubbing a method fail to take effect for internal self-calls, and what does recordPrivateCalls do?

level: seniorimportance: nice to knowfreq 25%

basics

~20 s

A spy wraps a real object. When one real method calls another method on itself, that inner call often runs the real one and skips your stub. recordPrivateCalls = true lets MockK see and verify private method calls.

open as a page