Roll Your Own Mock Framework

Level: Advanced 60–90 min

Concepts: MockingDesign PatternsBoundariesIncremental Design

Solutions: C# | TypeScript | Python


Build a basic mock object framework that lets developers create test doubles, set up return values, and verify method calls. Understanding how mocks work under the hood makes you better at using them.

Inspired by Jason Gorman’s Codemanship kata.

Requirements

Step 1: Create a Mock

Given an interface or class, create a mock instance that implements the same contract.

interface Calculator {
  add(a, b): number
  subtract(a, b): number
}

mock = createMock(Calculator)

The mock should accept any method call without throwing.

Step 2: Stub Return Values

Configure a mock to return specific values when methods are called with specific arguments.

when(mock.add(2, 3)).thenReturn(5)

result = mock.add(2, 3)  // returns 5
result = mock.add(1, 1)  // returns undefined/null (no stub configured)

Step 3: Verify Invocations

After exercising the system under test, verify that expected methods were called.

mock.add(2, 3)

verify(mock.add).wasCalledWith(2, 3)  // passes
verify(mock.add).wasCalledWith(1, 1)  // fails with meaningful message
verify(mock.subtract).wasCalled()      // fails — never called

Step 4: Meaningful Failure Messages

When verification fails, report what was expected vs what actually happened:

Expected: add(1, 1) to be called
Actual: add was called with (2, 3)

Test Cases

ScenarioExpected
Create mock from interfaceMock instance created, methods callable
Call unstubbed methodReturns null/undefined, no error
Stub return valueReturns configured value for matching args
Stub with different argsEach arg set returns its own value
Verify called methodPasses
Verify uncalled methodFails with message
Verify wrong argumentsFails with expected vs actual message
Verify call countwasCalledTimes(2) passes if called twice

Bonus

  • Support wasCalledTimes(n) — verify exact call count
  • Support wasNeverCalled() — verify a method was not invoked
  • Support argument matchers — verify(mock.add).wasCalledWith(anyNumber(), 3)
  • Support thenThrow(error) — mock throws instead of returning
  • Support call ordering — verify method A was called before method B

Hint

The core mechanic is a proxy that records all method calls (name + arguments) in a list. Stubbing adds entries to a return-value lookup. Verification searches the recorded calls. Start with recording calls and verifying them — add stubbing after.

Reference Walkthrough

Full C#, TypeScript, and Python implementations live at tddbuddy-reference-katas/roll-your-own-mock-framework with twelve scenarios across all three languages, a fluent when/verify API, and the domain exception VerificationError that distinguishes verification failures from unexpected errors. This is a meta-kata — the proxy mechanism diverges sharply per language (C# DynamicObject, TS Proxy with get trap, Python __getattr__).

This kata ships in Agent Full-Bake mode (middle gear) — a single commit per language with the full domain design. See the repo’s Gears section for why that’s a deliberate teaching choice.


  • The Test Pyramid Was an Economic Argument
    The test pyramid was not a quality law. It was a cost structure: unit tests were cheap, integration tests were expensive, so you wrote many of the first and few of the second. Agents collapsed the cost of writing tests at every level, and the cheapest test that still tells the truth is the one that pins a seam the agent cannot fake.
  • Agents Amplify Whatever Vocabulary They Find
    Agents do not bring vocabulary to your codebase. They mirror what's already there. Strong vocabulary gets agent contributions that read like the team. Weak vocabulary gets faster mediocrity. The work you did for craft reasons just became leverage.
  • The Hidden Output of TDD Was Never Code
    The visible artifact of TDD is a passing test suite. The actual artifact, the one that compounded value over the life of the codebase, was the vocabulary the team built while writing it. The dictionary, not the regression net.