繁体   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