簡體   English   中英

使用假的mongoDB進行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_stuffsomewhere_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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM