[Python] Can't accurately mock MongoDB calls, such as...

Discussão em 'Python' iniciado por Stack, Junho 20, 2025.

  1. Stack

    Stack Membro Participativo

    I'm using pytest and unittest.mock to unit test a pymongo class I've been creating.

    Here's example code:

    from pymongo import MongoClient
    import logging
    import traceback
    import time

    class mongo_client():


    def __init__(self):
    self.db = MongoClient("mongodb://localhost:27017/")
    self.db = self.db["TestDB"]

    logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
    self.logger = logging.getLogger(__name__)

    def log_network_down(self):
    try:
    status = {}
    status["online"] = False
    status["time"] = time.time()
    self.db["NetworkMonitor.logs.networkStatus"].insert_one(status)

    return True
    except:
    self.logger.error(f"A problem occurred in the log_network_down function")
    tb = traceback.format_exc()
    self.logger.exception(tb)
    return False


    Here's example test code:

    from mongo_client import mongo_client
    import pytest
    import unittest.mock as mock

    @pytest.fixture
    def mongo_client_instance():
    return mongo_client()

    class TestMongoClient():

    EPOCH_TIME_TEST = 1750110615.6034029
    MONGODB_OPERATION_ID = "1jhf2938yjoqyhiyuf0q"

    @mock.patch('time.time')
    def test_log_network_down_success(self, mock_time, mongo_client_instance):

    mock_time.return_value = self.EPOCH_TIME_TEST

    mock_collection = mock.MagicMock() #Mock return of self.db["NetworkMonitor.logs.networkStatus"]
    mock_insert = mock.MagicMock(acknowledged=True, inserted_id=self.MONGODB_OPERATION_ID) #Mock insert_one(status)
    mock_collection.insert_one.return_value = mock_insert #Mock self.db["NetworkMonitor.logs.networkStatus"].insert_one(status)

    #Mock the return of self.db["NetworkMonitor.logs.networkStatus"]
    with mock.patch.object(mongo_client_instance.db, '__getitem__', return_value=mock_collection) as mock_db_getitem:

    result = mongo_client_instance.log_network_down()

    assert result is True
    expected_status = {"online" : False, "time" : self.EPOCH_TIME_TEST}
    mock_db_getitem.assert_called_once_with("NetworkMonitor.info.currentNetworkStatus")
    mock_collection.assert_called_once_with(expected_status)

    mongo_client_instance.logger.error.assert_not_called()
    mongo_client_instance.logger.exception.assert_not_called()
    mock_time.assert_called_once()

    @mock.patch('time.time')
    @mock.patch('traceback.format_exc', return_value="Simulated Traceback Error")
    def test_log_network_down_failure(self, mock_format_exc, mock_time, mongo_client_instance):

    mock_time.return_value = self.EPOCH_TIME_TEST


    mock_collection = mock.MagicMock() #Mock return of self.db["NetworkMonitor.logs.networkStatus"]
    mock_insert = mock.MagicMock(acknowledged=True, inserted_id=self.MONGODB_OPERATION_ID) #Mock insert_one(status)
    mock_insert.side_effect = Exception("Simulated Error") #Add exception
    mock_collection.insert_one.return_value = mock_insert #Mock self.db["NetworkMonitor.logs.networkStatus"].insert_one(status)
    mock_collection.insert_one.side_effect = Exception("Simulated Error") #Add exception here as well just for testing. The previous exception should be enough

    #Mock the return of self.db["NetworkMonitor.logs.networkStatus"]
    #Mock exception error and exception messages
    with mock.patch.object(mongo_client_instance.db, '__getitem__', return_value=mock_collection) as mock_db_getitem, \
    mock.patch.object(mongo_client_instance.logger, 'error') as mock_log_error, \
    mock.patch.object(mongo_client_instance.logger, 'exception') as mock_log_exception:

    result = mongo_client_instance.log_network_down()

    assert result is False
    expected_status = {"online" : False, "time" : self.EPOCH_TIME_TEST}
    mock_db_getitem.assert_called_once_with("NetworkMonitor.info.currentNetworkStatus")
    mock_collection.assert_called_once_with(expected_status)

    mock_log_error.assert_called_once_with(f"A problem occurred in the log_network_down function")
    mock_log_exception.assert_called_once_with("Simulated Traceback Error")
    mock_time.assert_called_once()


    However, I'm encountering some issues.

    For the first test function, test_log_network_down_success has the following error.

    AssertionError: Expected '__getitem__' to be called once. Called 0 times.


    For the test

    mock_db_getitem.assert_called_once_with("NetworkMonitor.info.currentNetworkStatus")


    For the second test function, test_log_network_down_failure has the following error.

    assert True is False


    This indicates that the Exception I've assigned as a side_effect is not being thrown in my call to log_network_down. If the Exception would be thrown, the log_network_down function would return False.

    How can I properly mock my pymongo calls in my unit tests?

    Continue reading...

Compartilhe esta Página