liveBook · Manning

Mocking

As explained in Unit Testing Principles, Practices, and Patterns

Mocking is the practice of creating, configuring, or applying mocks in software tests.

Mocking creates test doubles for dependencies so tests can isolate behavior or verify communication. It improves tests only when it preserves resistance to refactoring; indiscriminate use creates fragility. section 5.0

Apply mocking through a small set of practical rules:

  • Mock unmanaged, usually out-of-process, dependencies; keep managed dependencies concrete unless a genuine abstraction has multiple implementations. section 8.4 section 9.3
  • Use mocks in controller integration tests rather than domain-model unit tests, because controllers coordinate communication while domain models handle business complexity. section 9.2
  • Verify interactions at the system’s edges, where application behavior meets an external dependency, rather than through an internal wrapper. section 9.1
  • Verify expected calls, call counts, and the absence of unexpected calls; the number of mocks depends on the behavior being tested, not a fixed quota. section 9.2 section 9.3
  • Mock adapters that you own instead of mocking third-party library types directly. section 9.3

Verify the external message, not the internal wrapper

A CRM email-change integration test initially mocks IMessageBus and verifies SendEmailChangedMessage. Because IMessageBus is an internal wrapper, the test can miss regressions in message translation. Construct MessageBus with a mock IBus instead, then verify the serialized external message once. A handwritten BusSpy offers the same edge-focused check while expressing the expected behavior without mock-framework syntax.

Listing 9.5. Integration test targeting IBus
[Fact]
public void Changing_email_from_corporate_to_non_corporate()
{
    var busMock = new Mock<IBus>();
    var messageBus = new MessageBus(busMock.Object);       #1
    var loggerMock = new Mock<IDomainLogger>();
    var sut = new UserController(db, messageBus, loggerMock.Object);

    /* ... */

    busMock.Verify(
        x => x.Send(
            "Type: USER EMAIL CHANGED; " +                 #2
            $"Id: {user.UserId}; " +                       #2
            "NewEmail: new@gmail.com"),                    #2
        Times.Once);
}

Shows an integration test that mocks the external IBus edge and verifies the emitted message. section 9.1

How Unit Testing Principles, Practices, and Patterns covers it

How deep it goes
Explains mock scope, test placement, edge targeting, call verification, owned adapters, and a refactoring from wrapper mock to edge mock.
Examples
Demonstrates CRM email changes, message-bus mocks, logger mocks, an IBus edge mock, and a handwritten BusSpy.
What it assumes
Assumes familiarity with unit and integration tests, dependency injection, interfaces, controllers, and unmanaged dependencies.
What you can do after
Apply it via mock frameworks or handwritten spies to verify observable interactions without coupling tests to internal wrappers.
How it connects
Connects mocking with test fragility, refactoring resistance, integration testing, unit testing, unmanaged dependencies, interfaces, and adapters.

Also explained in

Compare how 21 books explain mocking →

Related concepts

This explainer was generated by Manning's knowledge graph from the text of Unit Testing Principles, Practices, and Patterns. The section links point to the parts of the book it draws on.