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.

Medium Python 3.9+ Aug 9, 2026 System design patterns 13 views 0 copies

Python code

42 lines
Python 3.9+
from 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

stdout
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

  1. Use `unittest.mock.patch` to replace the entire class for testing without real instance methods.
  2. 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

Run this sample

Open the browser IDE to tweak the example and see results without installing anything.

Open editor

More from System design patterns

Related tutorials and quizzes for this topic.