![](/img/trans.png)
[英]Testing for MongoDB Functionality using Motor AsyncIO and Pytest
[英]Using a fake mongoDB for pytest testing
我有連接到MongoDB客戶端的代碼,我正在嘗試測試它。 為了測試,我不想連接到實際的客戶端,所以我試圖找出一個假的用於測試目的。 代碼的基本流程是我在某個地方創建了一個pymongo
客戶端,然后查詢並創建一個在其他地方使用的字典。
我想用pytest編寫一些測試,測試將調用get_stuff
不同函數和類。 我的問題是get_stuff
調用mongo()
,這實際上是與數據庫的連接。 我試圖只使用pytest.fixture(autouse=True)
和mongomock.MongoClient()
來替換mongo()
。
但這並沒有取代mongo_stuff.mongo()
。 有什么方法我可以告訴pytest替換一個函數,所以我的fixture
被調用而不是實際的功能? 我認為制作fixture
會使我的測試mongo()
在命名空間中的優先級高於實際模塊中的函數。
以下是我的示例的示例文件結構:
.
├── project
│ ├── __init__.py
│ ├── mongo_stuff
│ │ ├── __init__.py
│ │ └── mongo_stuff.py
│ └── working_class
│ ├── __init__.py
│ └── somewhere_else.py
└── testing
├── __init__.py
└── test_stuff.py
mongo_stuff.py
import pymongo
def mongo():
return pymongo.MongoClient(connection_params)
def get_stuff():
db = mongo() # Makes the connection using another function
stuff = query_function(db) # Does the query and makes a dict
return result
somewhere_else.py
from project.mongo_stuff import mongo_stuff
mongo_dict = mongo_stuff.get_stuff()
test_stuff.py
import pytest
import mongomock
@pytest.fixture(autouse=True)
def patch_mongo(monkeypatch):
db = mongomock.MongoClient()
def fake_mongo():
return db
monkeypatch.setattr('project.mongo_stuff.mongo', fake_mongo)
from poject.working_class import working_class # This starts by calling project.mongo_stuff.mongo_stuff.get_stuff()
這將導致我出現連接錯誤,因為mongo_stuff.py中的connection params
只能在生產環境中工作。 如果我將test_stuff.py中的import
語句放入測試函數中,那么它工作正常, mongomock
db將用於測試環境。 我也嘗試將setattr
更改為monkeypatch.setattr('project.working_class.mongo_stuff.mongo', fake_mongo)
,這也不起作用。
你已經到了一半:你已經為db客戶端創建了一個mongo_stuff.mongo
,現在你必須修補mongo_stuff.mongo
函數來返回模擬而不是真正的連接:
@pytest.fixture(autouse=True)
def patch_mongo(monkeypatch):
db = mongomock.MongoClient()
def fake_mongo():
return db
monkeypatch.setattr('mongo_stuff.mongo', fake_mongo)
為什么你的連接錯誤的原因是要導入somewhere_else
在模塊級的test_stuff
和somewhere_else
運行連接的代碼也在模塊水平。 因此,使用燈具進行修補將來得太晚,無效。 如果要在模塊級別導入,則必須在導入somewhere_else
之前修補mongo客戶端。 這樣可以避免錯誤提升,但是非常難看:
from project.mongo_stuff import mongo_stuff
import mongomock
import pytest
from unittest.mock import patch
with patch.object(mongo_stuff, 'mongo', return_value=mongomock.MongoClient()):
from project.working_class import somewhere_else
@patch.object(mongo_stuff, 'mongo', return_value=mongomock.MongoClient())
def test_db1(mocked_mongo):
mongo_stuff.mongo()
assert True
@patch.object(mongo_stuff, 'mongo', return_value=mongomock.MongoClient())
def test_db2(mocked_mongo):
somewhere_else.foo()
assert True
您應該盡可能避免在模塊級別上運行代碼,或者在測試中運行在模塊級別執行代碼的導入(正如您在評論中已經發現的那樣)。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.