Quick Start Guide

Getting started with Mongomock is straightforward. This guide covers how to set up and verify tests using direct database client injection or global runtime patching.

Method 1: Direct Client Injection

If your codebase accepts a database client or collection instance as an argument, you can pass a mongomock.MongoClient directly into your application components.

1. Write the Application Logic

Create a service class that manages user profile records:

# services.py
class ProfileService:
    def __init__(self, db_collection):
        self.collection = db_collection

    def update_user_email(self, user_id, new_email):
        if not new_email or "@" not in new_email:
            raise ValueError("Invalid email address format")

        result = self.collection.update_one(
            {"_id": user_id},
            {"$set": {"email": new_email, "updated_at": "modified"}},
            upsert=True
        )
        return result.modified_count == 1 or result.upserted_id is not None

2. Write the Unit Test

Test the service class in-memory with pytest using mongomock.MongoClient:

# test_services.py
import pytest
import mongomock
from services import ProfileService

def test_update_user_email_upsert():
    # Instantiate an in-memory client and collection
    client = mongomock.MongoClient()
    mock_collection = client.user_database.profiles

    service = ProfileService(mock_collection)

    # Execute the service call
    success = service.update_user_email("user_100", "user@example.com")

    # Assert return status
    assert success is True

    # Retrieve and verify document state from mock store
    document = mock_collection.find_one({"_id": "user_100"})
    assert document is not None
    assert document["email"] == "user@example.com"
    assert document["updated_at"] == "modified"

Method 2: Global PyMongo Patching

If your code handles client connections internally (such as instantiating pymongo.MongoClient inside function bodies), you can intercept those connections globally using the @mongomock.patch decorator.

1. Write the Application Code

# app.py
import pymongo

def register_login_event(host, username):
    # Connects internally to a target server
    client = pymongo.MongoClient(host)
    event = {
        "username": username,
        "login_time": "now"  # simplistic representation
    }
    client.analytics.login_logs.insert_one(event)

2. Write the Mock Test

Intercept the connection by specifying the target server address inside the patch decorator:

# test_app.py
import pymongo
import mongomock
from app import register_login_event

# Configure the decorator to intercept connections targeting database.internal
@mongomock.patch(servers=(('database.internal', 27017),))
def test_register_login_event():
    register_login_event("mongodb://database.internal:27017", "alice")

    # Establish a separate connection to verify the data in-memory
    verification_client = pymongo.MongoClient("mongodb://database.internal:27017")
    stored_log = verification_client.analytics.login_logs.find_one({"username": "alice"})

    assert stored_log is not None
    assert stored_log["login_time"] == "now"

Core Best Practices for Testing

  • Avoid Shared Client Pollution: Create a fresh mongomock.MongoClient instance for each test case. This keeps tests isolated and prevents data from leaking between runs.
  • Test Isolation with Decorators: When using @mongomock.patch, make sure it wraps test methods cleanly. This ensures that global mock states are cleared between test executions.
  • Use PyMongo Exceptions: If your production code catches database errors, run Mongomock with PyMongo installed (pip install mongomock[pymongo]). This ensures Mongomock throws real PyMongo exceptions like DuplicateKeyError or OperationFailure instead of its custom fallback classes.

Now that you have seen the basic setups, you can dive deeper into how Mongomock's memory, threads, and clocks work in the Core Concepts Guide.