skip to content

Object, Static & Constructor Mocking

mockkObject handles Kotlin objects and companions, mockkStatic covers top-level and static functions, and mockkConstructor intercepts instantiation. All three are global state, so unmockking in teardown is the discipline that keeps a suite reliable.

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

questions

5

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

open as a page

How does mockkStatic let you stub Kotlin top-level functions, extension functions, and Java static methods, and what do you pass to it?

level: middleimportance: must knowfreq 55%

basics

~10 s

mockkStatic tells MockK to intercept functions that have no instance — top-level functions, extension functions, and Java statics. You register the file/class, then stub with every { } and undo with unmockkStatic or unmockkAll.

open as a page

Why is teardown (unmockkObject/unmockkStatic/unmockkConstructor/unmockkAll) critical for object, static, and constructor mocks, and how do you guarantee it?

level: seniorimportance: must knowfreq 45%

basics

~20 s

Object, static, and constructor mocks change global JVM state shared by every test. If you don't undo them, the fake behavior leaks into later tests and causes flaky, order-dependent failures. Call unmockkAll in teardown to reset everything.

open as a page

What does mockkConstructor do, and how do you stub and verify calls on instances created with `new` inside the code under test?

level: seniorimportance: should knowfreq 40%

basics

~10 s

mockkConstructor(MyClass::class) makes every future MyClass(...) produce a mock. You then stub with every { anyConstructed<MyClass>().foo() } returns ... and verify with verify { anyConstructed<MyClass>().foo() }.

open as a page

Given a dependency you need to fake, how do you choose between mockkObject, mockkStatic, mockkConstructor, and a plain mockk — and when would you refactor instead?

level: principalimportance: should knowfreq 35%

basics

~20 s

Use a plain mockk for normal injectable classes. Use mockkObject for Kotlin objects/companions, mockkStatic for top-level/extension/Java-static functions, and mockkConstructor for objects newed up internally. The heavier the tool, the more it hints you should refactor to inject the dependency instead.

open as a page