我在模拟mongodb时需要帮助。我正在使用mongomock来模拟mongodb。
我的项目结构是:
-my_mongo.py
-code.py
-my_test.py
my_mongo.py 具有:
from pymongo import MongoClient
def get_db():
client = MongoClient(os.environ['MONGODB_URI'])
db = client['my_db']
return db
def insert(id, data):
return get_db().results.insert_one(
{
"id": id,
"data":df.to_json(),
}).id
和 code.py 具有
import my_mongo
def action():
#do somethings
my_mongo.insert(id, data)
和 my_test.py 具有
import mongomock
import my_mongo
from unittest import mock
with patch.object(my_mongo.get_db().client, "client", mongomock.MongoClient()):
import code
def test_action_1():
my_mongo.insert = mock.Mock(return_value=1)
code.action()
def test_action_2():
with patch.object(my_mongo.get_db(), "get_db", mongomock.MongoClient().db):
code.action()
这两个测试都抛出pymongo.errors.ServerSelectionTimeoutError。因此,它仍然进入my_mongo.py中的insert_one()方法。 我希望在test_action_1中my_mongo.insert返回1,但不会。
我想念什么?
答案 0 :(得分:0)
我不确定mongomock
的用途,但看起来它是用于模拟整个mongo数据库,而不是实际使用python模拟。我将不添加mongomock
来回答问题,因为我认为您并不是真的需要它,因此您可以以自己需要的价格接受它。
有几个问题:
调用patch.object
将在给定的任何对象上修补给定的方法。如果在测试中调用get_db
,则code.action
调用get_db
,这是2个不同的对象。也许行得通吗?但是我对此表示怀疑,所以我只是更改了它。
请勿使用code
作为模块名称。那已经是python附带的模块了。
code.action
缺少args和return语句。
您还将注意到,我更改了模拟的方式和内容,以说明完成模拟的不同方法。测试1使用函数装饰器模拟insert
调用。测试2使用get_db
模拟contextmanager
调用。两种方法都正确,只是表明您有选择。
这是成品:
my_mongo.py:
from pymongo import MongoClient
def get_db():
client = MongoClient(os.environ['MONGODB_URI'])
db = client['my_db']
return db
def insert(id, data):
return get_db().results.insert_one({"id": id, "data":data.to_json()}).id # df was undefined, updated to data
my_code.py:
import my_mongo
# I added id and data args. They were undefined
def action(id, data):
return my_mongo.insert(id, data) # I added a return here
my_test.py
from unittest import mock
import my_code
# I removed the contextmanager import. Nothing is being evaluated here that would
# need to be patched, so I'm pretty certain it has no effect
@mock.patch('my_mongo.insert')
def test_action_1(mock_insert):
expected_id = 1
mock_insert.return_value = expected_id
ret = my_code.action(expected_id, mock.Mock())
assert ret == expected_id
def test_action_2():
with mock.patch('my_mongo.get_db') as mock_get_db:
expected_id = 'some id'
mock_db = mock.Mock()
mock_db.results.insert_one.return_value.id = expected_id
mock_get_db.return_value = mock_db
ret = my_code.action(expected_id, mock.Mock())
assert ret == expected_id
答案 1 :(得分:0)
用于修补mongodb的那行代码是错误的。您应该使用patch.object(my_mongo.get_db(), "get_db", mongomock.MongoClient().db)
来代替patch.object("my_mongo.get_db", return_value=mongomock.MongoClient()['my_db'])
。
以下是您的示例的完整可运行代码:
my_test.py
import mongomock
from unittest.mock import patch
import my_code
import my_mongo
def test_action_2():
mocked_mongo = mongomock.MongoClient()
with patch("my_mongo.get_db", return_value=mongomock.MongoClient()['my_db']):
my_code.action()
assert mocked_mongo.my_db.results.count_documents({'id': 'some_id'}) == 1
my_mongo.py
from pymongo import MongoClient
def get_db():
client = MongoClient(os.environ['MONGODB_URI'])
db = client['my_db']
return db
def insert(id, data):
return get_db().results.insert_one(
{
"id": id,
"data": data,
})
my_code.py
import my_mongo
def action():
#do somethings
return my_mongo.insert('some_id', '{"a": 3}')