Contents

Engineering Craft › Testing

Stub

A test double that returns canned answers.

Also known as: stub, test stub, stubbing

A stub is a test double that returns canned answers. It stands in for a dependency so your test can control what the code under test receives, without calling the real thing.

class StubExchangeRates:
    def rate(self, currency):
        return 1.5                      # always the same answer

def test_price_in_euro():
    service = PriceService(rates=StubExchangeRates())
    assert service.price_in("EUR", 100) == 150
from unittest.mock import Mock
rates = Mock()
rates.rate.return_value = 1.5          # a stub made with a mocking library

What it’s for

  • Fixed inputs: a time, an exchange rate, a feature flag.
  • Forcing situations that are hard to create: a payment gateway that returns “declined”, a network that times out.
class DecliningGateway:
    def charge(self, amount):
        raise CardDeclined()
  • Speed and isolation: no network, no database.

Stub vs mock

A stub only supplies values. A mock also checks how it was called (“send_email was called once with these arguments”). If you only need the code to receive some data, use a stub, and assert on the result. See test doubles for the whole family.

Tips

  • Keep stubs dumb. If a stub needs logic, you’re approaching a fake.
  • Stub at boundaries (clocks, network, services), not your own internal code.
  • The code has to allow it: pass dependencies in (dependency injection).
  • Don’t over-stub. If everything is stubbed, the test only proves the stubs work (over-mocking).
  • A stub can drift from the real behavior, so keep some integration tests against the real thing.