After calling MockK's mockkConstructor(Foo::class), what does anyConstructed<Foo>() actually stand for, and which Foo instances does a stub recorded on it affect?
answer
- not an object — one shared handler per class
- all instances pooled, stubs and recorded calls alike
- unstubbed method runs the real code
- only instances constructed while mocked
- no per-instance identity
basics
~20 sanyConstructed<Foo>() is not an instance — it is a single shared handler for the class. Every Foo constructed while the class is mocked routes its calls through it, so one stub applies to all of them. Methods you never stub fall through to the real implementation.
solid answer
~50 s`mockkConstructor(Foo::class)` instruments the class so that instances created after that point are wired to MockK's dispatch. You never get a reference to those instances — the code under test creates them internally, which is the whole point of the feature. `anyConstructed<Foo>()` is the handle you use in `every` and `verify` to talk about them: a **single shared stub holder for the class**, not a particular object. So `every { anyConstructed<Foo>().send() } returns true` applies to the first, second and hundredth `Foo` the production code builds, and `verify { anyConstructed<Foo>().send() }` sees the calls made on all of them pooled together. Two further properties matter. Like MockK's other in-place transformations, it is **spy-like**: a method with no matching stub runs the real implementation. And the effect is bounded in time — instances constructed before `mockkConstructor` (or after the class is unmocked) behave completely normally.
code
kotlin · 7 linesmockkConstructor(MailClient::class)
every { anyConstructed<MailClient>().send(any(), any()) } returns true
notifier.notifyAll(users) // constructs a MailClient per user
verify { anyConstructed<MailClient>().send(any(), any()) }
unmockkConstructor(MailClient::class)go deeper
Say that anyConstructed refers to the class rather than one object, and that a stub on it covers every instance the code builds.
Add the spy-like fallthrough and the time boundary — only instances constructed while the class is mocked are affected.
Lead with the consequences: pooled recording, no per-instance identity, no automatic isolation, and the ordering trap with pre-existing instances.
Note that needing this at all means the code constructs its own dependencies, and treat each use as recorded coupling to a construction site.
## The problem it solves Sometimes the code under test creates its collaborator itself: ```kotlin fun notify(user: User) { val client = MailClient(config) client.send(user.email, "hi") } ``` There is no seam: you cannot inject a mock, because nothing is injected. MockK's constructor mocking gives you one by instrumenting the *class* so that the objects the production code builds are wired to MockK's dispatch. ## What anyConstructed is `mockkConstructor(MailClient::class)` installs that instrumentation. From then on, any `MailClient(...)` created by any code in the JVM is a **constructed mock**. The test never holds those objects, so MockK gives you a stand-in to record against: `anyConstructed<MailClient>()`. It is best understood as *the class's shared stub table*, not as an object. When you write ```kotlin every { anyConstructed<MailClient>().send(any(), any()) } returns true ``` you are saying: for every instance of this class created while it is mocked, a `send` call with any arguments answers `true`. The same handle is used for verification, and there the pooling is what surprises people: calls made on *different* instances are recorded together. Three instances each calling `send()` once produce three recorded `send` calls against `anyConstructed<MailClient>()`, not one each on three separate mocks. ## Spy-like fallthrough Constructor mocking is an in-place transformation, the same family as MockK's object and static mocking, and it behaves the same way: a call that matches a recorded stub is answered from the stub; a call that matches nothing runs the **real implementation**. That has two practical consequences. First, you are not automatically isolated. If the class opens a socket in a method you did not stub, that method still opens the socket. To keep a constructed collaborator inert you must stub every method the code under test will call — a stub with `any()` matchers per method is the usual shape. Second, absence of a stub is not an error. There is no strict-mock complaint pointing at the method you forgot; the test simply exercises real code, and the failure (if any) surfaces somewhere less obvious. ## When interception starts and stops The transformation is bounded in time, and reasoning about that boundary avoids most confusion: - Objects constructed **before** `mockkConstructor` ran are ordinary objects. Nothing retroactively converts them. A collaborator built in a field initializer, a lazily initialised singleton, or a setup hook that ran before the mock was installed will never be a constructed mock. - Objects constructed **while** the class is mocked route through the shared handler. - After the class is unmocked, construction is normal again. This is the first thing to check when a constructor mock "does nothing": very often the instance in question predates the call. ## The granularity limitation Because the handle is per class, you cannot say "the second instance should behave differently from the first" by identity — there is no identity to speak about. Your options are: - differentiate by **method arguments** (`every { anyConstructed<MailClient>().send(eq("a@b"), any()) } returns false`), which is often enough; - differentiate by **constructor arguments** using MockK's `constructedWith`, which filters instances by how they were built; - accept aggregate assertions and verify counts across all instances. ## Reading it back When you review a test that uses this feature, three questions cover most defects: are the instances actually created after the mock is installed; does every method the code calls have a stub, or are you happy for the real one to run; and does any assertion implicitly assume a single instance when several are constructed?
- A collaborator is created in a field initializer of the class under test, which the test instantiates in setup before calling mockkConstructor. Is that instance a constructed mock?No. Only instances constructed while the class is mocked are intercepted, and this one already existed. The fix is ordering: install the constructor mock before the object under test is created, or restructure so the collaborator is created at the point of use. This ordering trap is one of the most common reasons constructor mocking appears to do nothing.
- Does anyConstructed give you the isolation of a strict mock?No. Constructor mocking is spy-like: only calls matching a recorded stub are substituted, and everything else runs the real implementation. If the class performs I/O in a method you did not stub, the test performs that I/O. To be isolated you must stub every method the code under test reaches, usually with any() matchers.
saying these in an interview costs you the question
- Believing anyConstructed<T>() returns or refers to a specific instance
- Expecting unstubbed methods on a constructed mock to return null or throw
- Assuming objects created before mockkConstructor are also intercepted
- Thinking each constructed instance keeps its own separate recorded-call list
- Reaching for constructor mocking when the collaborator could simply be injected