Patching PyMongo Client
If your application code instantiates pymongo.MongoClient internally rather than accepting it as an injected dependency, you can intercept these instantiations using Mongomock's runtime patching framework.
How @mongomock.patch Works
The @mongomock.patch utility dynamically swaps the real pymongo.MongoClient class definition with a virtual client. This interceptor routes database calls to Mongomock's in-memory engine while preserving connection string configuration routing.
import pymongo
import mongomock
# Application Function
def fetch_database_status(connection_string):
# Connection is established internally
client = pymongo.MongoClient(connection_string)
return client.admin.command("ping")
# Test Definition
@mongomock.patch(servers=(('cluster.mongo.net', 27017),))
def test_internal_client_initialization():
# The real MongoClient is mocked during test execution
response = fetch_database_status("mongodb://cluster.mongo.net:27017")
assert response.get("ok") == 1.0
Server Routing and the on_new Policy
You can configure how Mongomock behaves when your application attempts to connect to a server address that was not defined in the servers parameter of @mongomock.patch:
@mongomock.patch(servers=(('localhost', 27017),), on_new='error')
on_new Policy Reference
'error'(Default): Raises aValueErrorimmediately. This is the strictest setting and is useful for catching misspelled hostnames or missing test configuration settings.'create': Dynamically spins up a new virtual in-memory server state. This is useful for systems with dynamically generated connection strings.-
'timeout': Simulates network partitions or offline database servers. The client will block for the duration of the timeout before raising aServerSelectionTimeoutError:import pymongo import mongomock from unittest import mock import time @mongomock.patch(on_new='timeout') @mock.patch('time.sleep') # Mock sleep to prevent test lag def test_database_unreachable(mock_sleep): with pytest.raises(pymongo.errors.ServerSelectionTimeoutError): pymongo.MongoClient("mongodb://non-existent-host:27017") -
'pymongo': Redirects connection requests to a real running MongoDB database via PyMongo. This is useful for hybrid integration tests where some services must hit a physical instance.
Decorator vs. Context Manager Syntax
You can apply patching using decorators or as inline context managers within individual test runs:
Using the Decorator
@mongomock.patch(servers=(('test-db', 27017),))
def test_with_decorator():
client = pymongo.MongoClient("test-db")
client.db.coll.insert_one({"key": "value"})
Using the Context Manager
def test_with_context_manager():
# PyMongo operates normally outside of this block
with mongomock.patch(servers=(('test-db', 27017),)):
client = pymongo.MongoClient("test-db")
client.db.coll.insert_one({"key": "value"})
Common Patching Pitfalls
Import Binding issues
Ensure your application code instantiates the database client via pymongo.MongoClient rather than binding it to a local namespace.
-
Incorrect (Will NOT be patched correctly):
# my_module.py from pymongo import MongoClient # The local binding 'MongoClient' is resolved before the patcher runs client = MongoClient("mongodb://test-db") -
Correct (Will be patched correctly):
# my_module.py import pymongo # Resolved dynamically at instantiation client = pymongo.MongoClient("mongodb://test-db")
Next, explore Mongomock's support for aggregation pipelines and query operators in the Aggregation Guide.