skip to content

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%

answer

  1. mockkConstructor intercepts new MyClass(...)
  2. Target with anyConstructed<T>()
  3. constructedWith<T>(EqMatcher(..)) filters by ctor args
  4. Real ctor body runs; stub per method
  5. Smell → prefer injecting the dependency

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() }.

solid answer

~40 s

`mockkConstructor(Foo::class)` intercepts the **constructor** so that any `Foo(...)` created afterwards — including instances the code under test news up internally, which you can't otherwise reach — becomes a mock. Because you don't hold the reference, you target it with the `anyConstructed<Foo>()` matcher: `every { anyConstructed<Foo>().bar() } returns 1` stubs every constructed instance, and `verify { anyConstructed<Foo>().bar() }` asserts. By default the real constructor body still runs (it's spy-like); pass `clear = true` or specify `localToThread`/recorded behaviour as needed. You can constrain by constructor args using a regular `mockk` constructor matcher with `constructedWith<Foo>(EqMatcher(...))`. Tear down with `unmockkConstructor(Foo::class)` or `unmockkAll()`. It's the heaviest of the three tools and a code smell — it usually means a collaborator should have been injected rather than instantiated inline.

code

kotlin · 12 lines
kotlin
class Calculator { fun sum(a: Int, b: Int) = a + b }
class OrderService { fun total() = Calculator().sum(1, 2) }

@AfterEach fun tearDown() = unmockkAll()

@Test
fun mocksInternallyNewedCollaborator() {
    mockkConstructor(Calculator::class)
    every { anyConstructed<Calculator>().sum(any(), any()) } returns 99
    assertEquals(99, OrderService().total())
    verify { anyConstructed<Calculator>().sum(1, 2) }
}

go deeper

for a junior

May only recognise the name; not expected to use it fluently.

for a middle

Can stub/verify with anyConstructed<T>() and knows it needs teardown.

for a senior

Knows constructedWith filtering, spy-like body execution, and its limitations.

for a principal

Treats it as a design smell and steers teams toward DI/factories so constructor mocking is unnecessary.

## The problem: un-injectable `new` Sometimes the code under test creates a collaborator itself: ```kotlin class OrderService { fun total(): Int = Calculator().sum(1, 2) // newed internally — no seam to inject } ``` You cannot pass a mock `Calculator` in. `mockkConstructor(Calculator::class)` installs an interceptor on the constructor so that **every instance created from then on** is a MockK proxy. ## Targeting instances you never see: anyConstructed Since the test never holds the constructed object, you reference it through the special matcher **`anyConstructed<T>()`**, which represents "any instance produced via the mocked constructor": ```kotlin mockkConstructor(Calculator::class) every { anyConstructed<Calculator>().sum(any(), any()) } returns 99 assertEquals(99, OrderService().total()) verify { anyConstructed<Calculator>().sum(1, 2) } ``` ## Constraining by constructor arguments If you only want to affect instances built with specific args, use `constructedWith`: ```kotlin mockkConstructor(Calculator::class) every { constructedWith<Calculator>(EqMatcher(2)).scale() } returns 4 ``` This matches only `Calculator(2)` instances. ## Spy-like by default Like `mockkObject`, the **real constructor body runs** unless you stub the methods you care about; only stubbed methods are faked. There is no `relaxed` blank-instance creation — you opt into behaviour per method. ## Teardown Constructor interception is global JVM state. Reset with `unmockkConstructor(Calculator::class)` or `unmockkAll()` in `@AfterEach`. The `mockkConstructor(Foo::class) { }` lambda form auto-unmocks. ## Limitations and smell - It cannot intercept constructors of `final`/inline value classes the same way and has caveats with classes the JVM has already heavily inlined. - It is the most invasive of the three (`mockkObject`/`mockkStatic`/`mockkConstructor`). - Reaching for it is usually a sign the design hides a dependency. The cleaner fix is **dependency injection** — pass a `Calculator` (or a factory `() -> Calculator`) into `OrderService` so a plain `mockk<Calculator>()` suffices, no bytecode constructor patching needed.

  • How do you reference an object you never get a handle to because the code newed it internally?
    Use the anyConstructed<T>() matcher inside every {} / verify {}; it represents any instance produced through the mocked constructor.
  • When would you refactor instead of using mockkConstructor?
    Almost always: if you control the class, inject the collaborator (or a factory) so a plain mockk<T>() works. Reserve mockkConstructor for third-party classes you can't change.

It's like rigging the factory so every car coming off the line is secretly a remote-controlled dummy, even ones you never ordered.

saying these in an interview costs you the question

  • Trying to capture the constructed instance into a variable instead of using anyConstructed<T>()
  • Believing the constructor body is skipped (it runs unless methods are stubbed)
  • Treating mockkConstructor as a first choice rather than a last resort
  • Forgetting unmockkConstructor/unmockkAll teardown

context