liveBook · Manning

Output-based testing

As explained in Unit Testing Principles, Practices, and Patterns

Output-based testing evaluates software by comparing explicitly produced outputs with expected outputs rather than verifying internal interactions.

Output-based testing feeds an input to the system under test and verifies the value it returns. It applies when the code has no hidden inputs, hidden outputs, or side effects. section 6.1 section 6.6

The strongest tests target observable behavior through the method under test alone. They usually resist refactoring better, remain concise, and cost less to maintain than state-based or communication-based tests. section 6.2 section 6.6

Choose the testing style according to what the operation visibly produces:

  • Use output-based testing for pure calculations whose inputs and outputs appear explicitly in the method signature. section 6.3
  • Use state-based testing when the operation’s outcome is a changed object, collaborator, database, or filesystem state. section 6.1
  • Use communication-based testing sparingly, verifying only external interactions whose side effects are visible outside the application. section 6.2

Testing a discount calculation

PriceEngine.CalculateDiscount receives products and returns a discount capped at 20 percent. A test supplies two products and asserts 0.02 as the returned value, without inspecting internal state or interactions.

Refactoring filesystem work into outputs

An audit manager initially reads and writes files directly, making tests slow and difficult to maintain. Refactoring separates a functional AuditManager, which returns a FileUpdate, from a mutable Persister that applies it. The test then compares the returned update directly, without mocks. section 6.4

How Unit Testing Principles, Practices, and Patterns covers it

How deep it goes
Defines the style, compares its trade-offs, and demonstrates refactoring toward functional architecture without deeply teaching functional programming.
Examples
Uses discount calculation and audit-file refactoring examples, including direct value comparisons and returned file updates.
What it assumes
Assumes unit-testing familiarity, then teaches the distinction between testing styles and the basics of pure functions from first principles.
What you can do after
Apply output-based testing by asserting returned values and moving side effects toward a functional core with a mutable shell.
How it connects
Connects output-based testing with pure functions, functional programming, functional architecture, hexagonal architecture, state-based testing, and communication-based testing.

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.