2 minute read

To save on resources and time when testing a software product or application, substitute software components and layers using test doubles.

Summary

Type Reproduces Executes Original Code Behavioral Fidelity Typical Purpose Example
Stub Minimal interface — fixed outputs only Very low Isolate a unit under test by providing the bare minimum responses A function that always returns 200 OK without logic
Fake Simplified but working implementation Low–Medium Speed up tests or development with lightweight logic In-memory DB that mimics CRUD but stores data in a list
Mock Interface with expectations on interactions Medium Verify that a component calls dependencies correctly Verifying sendEmail() was called once with args X
Simulator Modeled functional behavior (approximated dynamics) High (functional) Predict or observe system behavior under controlled conditions Flight simulator modeling aerodynamics numerically
Emulator Full operational semantics — identical observable behavior Very high (causal & binary compatible) Run or analyze software built for another system QEMU running an ARM binary on x86

Types

Stub

A stub provides the bare minimum behaviour to satisfy an interface.

Think of how a car requires 4 wheels to be taken off a jack; a pile of bricks is a stub meeting the bare minimum for the wheel mounting interface.

Do ✅:

  • Return predefined responses.
  • Log warnings.
  • Raise exception on pre-condition failure.
  • Raise exception on post-condition failure.

Don’t ❌:

  • Record interactions as interal state.
  • Provide additional behaviour outside of satisfying the interface.
  • Implement behaviour that is beyond constant time complexity.

Unlike most doubles, stubs can be suitable for production, such as when a polymorphic API does not support optional composition. For example, a function callback that must point to a function; a stub function is a reasonable design choice.

Fake

A fake is a custom component that provides limited or degraded behaviours of the real component.

Unlike most doubles, Fakes don’t necessarily match a desired production interface. Fakes are primarily utilities for faking the complex behaviours and may be decoupled from versioned interfaces for reusability via composition inside other test doubles.

Mock

A mock is a behavioural test double usually used in unit tests that:

  • is interface compliant
  • is behaviourally compliant where it needs to be
  • have additional observational behaviors that may violate immutability constraints

The advantage of using mocks in testing is that they:

  • Can utilize fake behaviour to run much faster than the real components
  • Can utilize spy behaviour to observe how it was interacted with by the real component, such as:
    • Call counts
    • Call order
    • Call arguments

Simulator

Simulators are large, complex, executable models for the behaviour of another system. The advantage of simulators is that they support running under controlled and typically configurable conditions, unlike the conditions of the real system.

Emulator

Emulators are systems that substitute for an entire platform and execute the real system instructions inside it. They typically perform 1-to-1 translations of entire hardware layers to decouple testing from physically scarce hardware.

Very similar to emulators are compatibility layers, which intentionally simplify or skip certain behaviours deemed not important for typical use, or serve as an adapter for inputs and outputs.

Testing Resources

https://principal-it.eu/blog.html

Tags:

Categories:

Updated: