skip to content

How do you use mockkObject to stub a method on a Kotlin object (singleton) or companion object in a MockK test?

level: juniorimportance: must knowfreq 60%

answer

  1. object = JVM singleton → can't mockk<T>()
  2. mockkObject = in-place spy on the real instance
  3. Unstubbed methods run real code
  4. Teardown with unmockkObject / unmockkAll
  5. Companion: mockkObject(Class) or Class.Companion

basics

~10 s

Call mockkObject(MyObject) to turn the real singleton into a spy, then use every { MyObject.foo() } returns ... to fake a method. Clean up afterwards with unmockkObject or unmockkAll.

solid answer

~40 s

A Kotlin `object` (and a `companion object`) is a JVM singleton, so you cannot pass it to the normal `mockk<T>()` constructor — you mock the existing instance in place with `mockkObject(MyObject)`. This wraps the real singleton so unstubbed calls still run the original code (it behaves like a spy). You then stub with `every { MyObject.compute() } returns 42` and assert with `verify { MyObject.compute() }`. For a companion, pass the companion reference: `mockkObject(Repo.Companion)` or `mockkObject(Repo)` depending on how the factory method is declared. Always undo the global state in teardown via `unmockkObject(MyObject)` or, more commonly, `unmockkAll()` in an `@AfterEach`, otherwise the mock leaks into other tests because the singleton is shared JVM-wide.

code

kotlin · 13 lines
kotlin
object Clock {
    fun now(): Long = System.currentTimeMillis()
}

@AfterEach fun tearDown() = unmockkAll()

@Test
fun freezesTime() {
    mockkObject(Clock)
    every { Clock.now() } returns 1_000L
    assertEquals(1_000L, Clock.now())
    verify(exactly = 1) { Clock.now() }
}

go deeper

for a junior

Knows mockkObject(Obj) + every {} + cleans up with unmockkAll.

for a middle

Explains the spy semantics (unstubbed = real) and why mockk<T>() fails on singletons.

for a senior

Discusses leaked global state, ordering risk, recordPrivateCalls, and the lambda auto-unmock form.

for a principal

Frames object mocking as testing around global state and argues for refactoring singletons toward injectable interfaces to avoid it.

## What problem mockkObject solves In Kotlin an `object` declaration is a **singleton** — there is exactly one instance for the whole JVM, created lazily on first access. A `companion object` is the same: one shared instance attached to its enclosing class. Because you never call a constructor for these, you cannot do `mockk<MyObject>()` — there is nothing to instantiate and substitute. `mockkObject` instead **instruments the already-existing singleton instance in place**. ## How it behaves: a spy, not a blank mock `mockkObject(MyObject)` makes the singleton behave like a **spy**: methods you do NOT stub keep running their **real implementation**; only the ones you override with `every { ... }` are faked. This differs from `mockk<T>()`, which is a blank mock where every unstubbed call throws (or returns default with `relaxed = true`). ```kotlin object PriceService { fun base(): Int = 100 fun withTax(): Int = base() + 20 } @Test fun stubsSingleton() { mockkObject(PriceService) every { PriceService.base() } returns 0 // withTax() is NOT stubbed, so it runs real code calling the stubbed base() assertEquals(20, PriceService.withTax()) verify { PriceService.base() } unmockkObject(PriceService) } ``` ## Companion objects A factory on a companion is mocked the same way: ```kotlin class User private constructor(val id: String) { companion object { fun create(id: String) = User(id) } } // mockkObject(User.Companion) or mockkObject(User) both target the companion mockkObject(User) every { User.create(any()) } returns User.create("stub") ``` ## Teardown is mandatory Because the singleton is **global mutable state**, the mock survives across tests in the same JVM. Undo it with `unmockkObject(MyObject)` for that one object, or `unmockkAll()` (in `@AfterEach`/`@After`) to reset every MockK registration — objects, statics, constructors. Forgetting this causes flaky, order-dependent failures. ## Useful options - `mockkObject(A, B)` mocks several objects in one call. - `mockkObject(MyObject, recordPrivateCalls = true)` lets you verify private calls. - `objectMockk(...) { ... }` / the `mockkObject(...) { }` lambda form auto-unmocks at the end of the block.

  • Why can't you just write mockk<MyObject>() for a Kotlin object?
    Because an object is a singleton with no public constructor; mockk<T>() creates a brand-new instance, which would not be the singleton other code already references. mockkObject patches the single shared instance.
  • After mockkObject, is an unstubbed method faked or real?
    Real — mockkObject behaves like a spy, so only explicitly stubbed methods are overridden; everything else runs the original implementation.

It's like putting a wiretap on the one phone everyone shares, instead of handing out a fake phone.

saying these in an interview costs you the question

  • Claiming you mock an object with mockk<MyObject>()
  • Forgetting teardown, causing leaked global state across tests
  • Assuming unstubbed methods return null/defaults like a blank mock
  • Not knowing a companion object is also a singleton you target the same way

context