Mock Unit of Work commit and rollback in Python
Verify that a Unit of Work pattern commits on success and rolls back on failure using unittest.mock in Python.
Python code
42 linesfrom unittest import mock
class UnitOfWork:
def __init__(self):
self.committed = False
self.rolled_back = False
def commit(self):
self.committed = True
print("Commit executed")
def rollback(self):
self.rolled_back = True
print("Rollback executed")
def business_operation(uow):
try:
# Some work...
uow.commit()
except Exception:
uow.rollback()
raise
if __name__ == "__main__":
uow = UnitOfWork()
# Mock the commit and rollback methods to verify calls
with mock.patch.object(uow, "commit") as mock_commit, mock.patch.object(uow, "rollback") as mock_rollback:
business_operation(uow)
mock_commit.assert_called_once()
mock_rollback.assert_not_called()
print("Success path: commit called, rollback not called")
# Simulate a failure to test rollback
with mock.patch("__main__.business_operation", side_effect=Exception("Simulated failure")):
try:
business_operation(uow)
except Exception:
print("Failure path: exception raised as expected")
Output
Commit executed
Success path: commit called, rollback not called
Failure path: exception raised as expected
How it works
The UnitOfWork class encapsulates transactional boundaries with commit and rollback methods. The business_operation function simulates work and calls commit on success, or rollback and re-raises on exception. Using mock.patch.object replaces the real methods with mocks, allowing assert_called_once and assert_not_called to verify call behavior in tests. The second test mocks the entire business_operation to trigger an exception, demonstrating rollback coverage. This pattern ensures transactional integrity in production by separating the unit of work from business logic.
Common mistakes
- Forgetting to call `mock.patch.object` inside a `with` block, leaving mocks active beyond the test scope.
- Not restoring the original methods after mocking, causing side effects in other tests.
- Mocking `commit` and `rollback` but not verifying they are called with correct arguments.
- Assuming the rollback path is automatically tested without simulating an exception.
Variations
- Use `unittest.mock.patch` to replace the entire class for testing without real instance methods.
- Wrap `business_operation` in a context manager to handle commit/rollback automatically.
Real-world use cases
- Unit testing a service layer that uses a Unit of Work to manage database transactions.
- Verifying that an API endpoint calls commit only on successful data processing, not on validation errors.
- Testing a batch job that must roll back partial changes when any item in the batch fails.
Sponsored
More from System design patterns
- Build a BFF (Backend for Frontend) Mock Aggregator in Python medium
- Builder pattern for mocking complex objects in Python easy
- Circuit Breaker Pattern in Python: Closed, Open, and Half-Open States medium
- Create a Data Helper Class in Python easy
- Domain Driven Design Aggregate Root Example in Python medium
- Facade Pattern in Python with Mock Simplification medium
Keep learning
Related tutorials and quizzes for this topic.