---
title: "Test Doubles and Testing at a Boundary"
description: "A test double replaces a dependency with a stand-in the test controls. A seam allows that substitution. Checking public results and contract-relevant boundary interactions can reduce dependence on int"
canonical: https://lightmysky.com/learn/computing/test-doubles-and-testing-at-a-boundary-mt_4ep3SiMYNM
source: https://lightmysky.com/learn/computing/test-doubles-and-testing-at-a-boundary-mt_4ep3SiMYNM.md
retrieved: 2026-11-12
---

> **Agent view.** This is the Markdown twin of the page, for tools and assistants.
> When to use this site, and the call that answers each job: https://lightmysky.com/agent-instructions.md
> API description (OpenAPI 3.1): https://lightmysky.com/openapi.json · Authentication: https://lightmysky.com/auth.md
> Pricing: https://lightmysky.com/pricing.md · Catalog: https://lightmysky.com/llms.txt · Full catalog: https://lightmysky.com/llms-full.txt
> Every machine-readable file on this domain: https://lightmysky.com/.well-known/ai-catalog.json
> Ask for Markdown with `Accept: text/markdown`, a `.md` address, or `?mode=agent`.

# Test Doubles and Testing at a Boundary

A test double replaces a dependency with a stand-in the test controls. A seam allows that substitution. Checking public results and contract-relevant boundary interactions can reduce dependence on internal structure.

Subject: Computing · Area: Software Engineering · Ages 20 to 21
Page: https://lightmysky.com/learn/computing/test-doubles-and-testing-at-a-boundary-mt_4ep3SiMYNM

## Ready when they can

- Replace a real dependency with a stand-in and test the logic around it
- Distinguish a stub that returns canned answers from a mock that checks calls
- Explain how assertions tied to private helpers can break during behaviour-preserving refactoring

## Lesson: Stand-ins for awkward neighbours

A test double is a stand-in for a dependency such as a database, clock or network client. A seam is a place where the test can substitute it. Use a double when controlling the dependency helps test your logic. It must supply the interface and behaviour relevant to that test, not reproduce the whole real system.

**Example.** Suppose a greeting function reads an hour through a clock dependency. A stub clock returns a chosen hour without reading wall time. Returning 9 lets the test exercise the before-noon case whenever it runs. Other uncontrolled dependencies could still affect the result.

A stub supplies chosen responses. A mock supports checking interactions, such as which request was made. One test-double object can do both jobs: return a chosen row and record calls. These names describe testing roles; recording is not a capability exclusive to mocks.

For time-dependent greeting logic, put a seam where the logic obtains the hour. Pass in a clock object or function with the expected interface. The test can then supply a fixed hour while leaving the greeting logic under test. A seam inside formatting code would not control the time source.

An interaction check is useful when an outward request is part of the contract. If the contract requires requesting user 42 from a database dependency, record that boundary request and check its argument. Returning a canned row alone does not establish which request was made.

Assertions about private helpers can couple tests to structure. If an assertion names a private helper, renaming that helper may break the assertion even when public behaviour is preserved. Not every refactoring causes this. Check public results and contract-relevant boundary interactions where possible.

*(drawing: Receiving a dependency exposes a seam. Passing this test does not establish that the real database works.)*

A mock configured to return a chosen network response can be used without asserting on recorded calls. In that test it supplies the stub role. Checking the final message may be enough for the stated contract. Merely naming an object a mock does not remove network access; the dependency must actually be replaced.

**Recap.** Control dependencies through a seam. Check public results and required boundary requests. A double does not test the real dependency.

*Original lesson, questions and flashcards written for this learning dataset.*

## Practice

8 questions on this page, each with its working shown.

## Needs first

- [Refactoring: Changing Structure Without Changing Behaviour](https://lightmysky.com/learn/computing/refactoring-changing-structure-without-changing-behaviour-mt_HHZufOyTg4)

## Optional connections

- [Interfaces, coupling and what a module promises](https://lightmysky.com/learn/computing/interfaces-coupling-and-what-a-module-promises-mt_EUZyD26WFk)

## Opens up

- [Test Strategy: Unit, Integration and End to End](https://lightmysky.com/learn/computing/test-strategy-unit-integration-and-end-to-end-mt_fdAvx1MMFE)
