A mock replaces a collaborator in a test so the caller’s response to a selected result or failure can be observed.
Python unittest.mock: inject a collaborator failure before publication
Operation contract
The importer stages one receipt, asks a writer to publish it, and updates its accepted list only after that writer succeeds. A spec-limited mock raises an OSError. The test checks that the list remains empty and the writer received exactly the staged record. This tests an application boundary rather than every internal line.
Failure and ownership boundary
The injected writer models one synchronous call that either returns or raises before a successful publication is reported. It does not simulate a remote write that commits and then loses its acknowledgment. That case needs idempotency and reconciliation. Python SQLite job project: reject conflicting replays by request identity and Python file project: stage a report before replacing the visible file address the ambiguity.
Working program
from unittest.mock import Mock
class ReceiptWriter:
def publish(self, receipt):
raise NotImplementedError
def import_receipt(receipt, writer, accepted):
staged = dict(receipt)
writer.publish(staged)
accepted.append(staged["receipt_id"])
writer = Mock(spec_set=ReceiptWriter)
writer.publish.side_effect = OSError("fixture writer unavailable")
accepted = []
try:
import_receipt({"receipt_id": "R-0041", "amount": 125}, writer, accepted)
except OSError:
print("writer failure propagated")
writer.publish.assert_called_once_with({"receipt_id": "R-0041", "amount": 125})
print("accepted:", accepted)Output
writer failure propagated
accepted: []Costs and limits
The fixture makes one bounded collaborator call and an outer record copy. Mocks do not measure real I/O latency or establish compatibility with the actual writer. Separate integration tests need to exercise that implementation.
Common Mistakes
- Mock the boundary the caller actually uses.
- A timeout after remote commit is not the same as this pre-publication failure.
Connected lessons
Pytest fixtures: isolated files and parameterized rejection tests, Python SQLite job project: reject conflicting replays by request identity, Python file project: stage a report before replacing the visible file.
Check this related boundary
Python unittest.mock: patch the name the caller actually resolves, Python testing: autospec catches a changed call signature.
