代码之家  ›  专栏  ›  技术社区  ›  TheStrangeQuark

使用伪mongoDB进行pytest测试

  •  3
  • TheStrangeQuark  · 技术社区  · 6 年前

    我有连接到MongoDB客户机的代码,我正在尝试测试它。对于测试,我不想连接到实际的客户机,所以我试图找出一个用于测试目的的假客户机。代码的基本流程是我在某个地方有一个函数 pymongo 客户机,然后查询它并生成一个在别处使用的dict。

    get_stuff . 我的问题是 去拿些东西 mongo() 这就是连接到数据库的原因。我只是想利用 pytest.fixture(autouse=True) mongomock.MongoClient() mongo() .

    但这并不能取代 mongo_stuff.mongo() . 有什么方法可以让pytest替换一个函数 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èu 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
    

    from project.mongo_stuff import mongo_stuff
    
    mongo_dict = mongo_stuff.get_stuff()
    

    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()
    

    这将给我一个连接错误,因为 connection params 在里面 mongoèu stuff.py网站 只能在生产环境中工作。如果我把 import 声明来自 转换成一个测试函数,然后它就可以正常工作了 mongomock db将用于测试环境。我也试着改变 setattr monkeypatch.setattr('project.working_class.mongo_stuff.mongo', fake_mongo) 这也不起作用。

    1 回复  |  直到 6 年前
        1
  •  7
  •   hoefling    6 年前

    您已经完成了一半:您已经为db客户机创建了一个mock,现在您必须修补 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 ,和 在别的地方 进口 如果要在模块级导入。这将避免错误,但非常难看:

    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
    

    您应该尽量避免在模块级运行代码,或者在测试中运行在模块级执行代码的导入(正如您在注释中已经发现的那样)。