Пример с изменением курсора для проверки случая, когда набор результатов пуст:
from unittest.mock import patch, MagicMock
from pymongo.mongo_replica_set_client import MongoReplicaSetClient
from pymongo.cursor import Cursor
import testee
def test_empty_result_set():
db_data_mock = MagicMock(spec=Cursor)() # 1
db_data_mock.count.return_value = 0 # 2
db_conn_mock = MagicMock(spec=MongoReplicaSetClient)() # 3
db_conn_mock.__getitem__().__getitem__().find.return_value = db_data_mock
with patch('commons.db_connection', return_value=db_conn_mock): # 4
assert not testee.check_entries() # 5
подробности:
MagicMock(spec=Cursor)
возвращает класс, имитирующий pymongo.cursor.Cursor
класс. db_data_mock
является экземпляром этого фиктивного класса.
db_data_mock.count.return_value = 0
проверяет метод count
, поэтому он всегда возвращает ноль.
Следующие две строки: создайте фиктивный экземпляр для pymongo.mongo_replica_set_client.MongoReplicaSetClient
(так же, как в 1.) и подключите к нему экземпляр курсора, чтобы метод find()
всегда возвращал db_data_mock
экземпляр, который мы создали ранее .
- Наконец, замените функцию
commons.db_connection
на смоделированную, которая возвращает наш MongoReplicaSetClient
фиктивный объект.
- Все приготовления сделаны; сделать реальный тест.
Обновление: тест, который не использует unittest
, был запрошен в комментариях
Если по какой-то странной причине «чистоты» вы не хотите трогать код unittest
, вам нужно либо найти заменяющую библиотеку для этого, либо написать макеты самостоятельно. pytest
не предлагает функции насмешки из коробки. Пример выше без unittest
может выглядеть так:
from collections import defaultdict
import testee
class CursorMock:
def count(self):
return 0
class ConnectionMock:
def find(self):
return CursorMock()
class MongoReplicaSetClientMock:
def __getitem__(self, name):
return defaultdict(ConnectionMock)
def db_connection_mock(*args, **kwargs):
return MongoReplicaSetClientMock()
def test_empty_result_set(monkeypatch):
monkeypatch.setattr(commons, 'db_connection', db_connection_mock)
assert not testee.check_entries()
Вместо unittest.mock.patch
использовался прибор monkeypatch
.
Обратите внимание, что, хотя есть некоторые плагины для pytest
, которые предлагают имитацию (например, pytest-mock
), большинство из известных мне просто удобные обертки вокруг unittest.mock
и все еще используют это под капотом.