我有一个名为commons.py的脚本,其中包含一些最常用的函数。
在我的主脚本中,我正在创建一个mongo连接对象:
db_ob = commons.db_connection()
db_connection返回一个MongoReplicaSetClient连接对象。
如何为我的下面的函数编写测试用例??
def check_entries():
try:
db_ob = commons.db_connection()
except:
print('Unable to connect to db!!')
return False
db_name = 'my_db_name'
collection_name = 'my_collection_name'
db_data = db_ob[db_name][collection_name].find()
if db_data.count() == 0:
print('No entries found in the collection!')
return False
return True
我可以模拟我的db_connection函数,但是我在模拟.count()和.find()函数时遇到了问题。
答案 0 :(得分:1)
模拟光标以在结果集为空时测试大小写的示例:
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()
方法始终返回{{1我们之前创建的实例。
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()
使用了http://edgeguides.rubyonrails.org/action_controller_overview.html#strong-parameters。
请注意,尽管unittest.mock.patch
有一些插件提供了模拟功能(例如,monkeypatch
fixture),但我所知道的大多数只是pytest
周围的方便包装,仍然使用它引擎盖下。
答案 1 :(得分:0)
我的解决方案:
由于db_connection函数正在返回一个对象,我使我的mock函数返回一个对象,并且内置了所需的函数。
我开始使用所需的函数创建一个类,并以所需的格式返回对象。
基于各种情况(成功/不成功连接,各种计数值等),可能有几个模拟函数。
def mock_db_connection_success(*args, **kwargs):
"""Function to mock successful db connection."""
class ReturnClass(object):
"""."""
@staticmethod
def __init__(*args, **kwargs):
"""."""
pass
# @staticmethod
def find(self, *args, **kwargs):
"""."""
return self
@staticmethod
def count(*args, **kwargs):
"""."""
return 1
class_ob = ReturnClass()
return {"my_db_name": {"my_collection_name": class_ob}}
@mock.patch('my_script.commons.db_connection', side_effect=mock_db_connection_success)
def test_function(*args, **kwargs):
"""Test Function."""
# use the function here
我还使用python库找到了相同的实现:flexmock
使用该库,我们不需要为类编写完整的定义,并且可以使用最低限度的定义来完成。它为更快地编写各种案例提供了很多帮助。