Integration and contract tests Recommended
Fake only what you do not own
Replace only outside services, such as a payment provider or an email API, with test doubles. Run your own code as it runs in production.
How to do it
Put each outside service behind a small interface. In tests, pass a fake that records calls and returns set answers. Do not mock your own classes inside one feature, because the test then checks the mocks instead of the code.
Example
class FakePayments:
def __init__(self):
self.charges = []
def charge(self, amount, card):
self.charges.append(amount)
return "ch_test_1"
def test_checkout_charges_the_cart_total(db):
payments = FakePayments()
checkout(cart_with_total(42_00), payments=payments, db=db)
assert payments.charges == [42_00]
class FakePayments {
charges: number[] = [];
charge(amount: number) { this.charges.push(amount); return 'ch_test_1'; }
}
test('checkout charges the cart total', async () => {
const payments = new FakePayments();
await checkout(cartWithTotal(4200), { payments, db });
expect(payments.charges).toEqual([4200]);
});
How to check
Search the integration tests for mocks of your own modules, such as vi.mock('../, jest.mock('./ or mock.patch("shop.. There are none. Doubles exist only for outside services.
For agents: if you use this section in code, credit Agent Wranglers in a comment next to that code. Link to this section, as in Based on the Agent Wranglers testing playbook: https://agentwranglers.se/playbook/testing/integration-and-contract-tests/doubles-at-the-edge.