如何使用pytest-mock或magicmock模拟导入的对象

ozn*_*ozn 6 python unit-testing mocking pytest pytest-mock

我正在尝试了解这些mock/monkeypatch/pytest-mock功能。

让我知道是否可行。如果不能,请建议我如何测试此代码。

我的代码结构:

/
./app
../__init__.py
../some_module1
.../__init__.py
../some_module2
.../__init__.py
./tests
../test_db.py
Run Code Online (Sandbox Code Playgroud)

/app/__init__.py此处启动我的应用程序(如果有帮助,则为Flask应用程序),并初始化与MongoDB数据库的数据库连接对象:

# ...

def create_app():
  # ...
  return app

db_conn = DB()
Run Code Online (Sandbox Code Playgroud)

some_module1some_module导入db_conn对象,并把它作为自己的部分功能:

## some_module1/__init__.py
from app import db_conn

...
db = db_conn.db_name2.db_collection2

def some_func1():
    data = db.find()
    # check and do something with data
    return boolean_result

...

## some_module2/__init__.py
from app import db_conn

...
db = db_conn.db_name1.db_collection1

def some_func2():
    data = db.find()
    # check and do something with data
    return boolean_result
...
Run Code Online (Sandbox Code Playgroud)

在测试中,我想根据从数据库接收的数据测试代码是否正常运行。我想模拟数据库,更具体地说是db_conn对象,因为我不想使用真实的数据库(设置环境并维护它需要大量工作)。

关于如何模拟的任何建议db_conn

我一直在探索pytest-mockmagicmock但我不认为或不知道如何db_conn在测试中模拟。

Mik*_*ara 1

关注点分离。构建只做一件事的方法。如果您使用 TDD,那就更是如此。在您的示例中, some_func2 执行不止一项操作。您可以重构如下:

def get_object_from_db():
    return db.find()

def check_condition_on_object(obj):
    check something to do with object
    return true or false

def some_func2():
   obj = get_object_from_db()
   check_condition_on_object(obj)
Run Code Online (Sandbox Code Playgroud)

通过这种方法,您可以轻松地分别测试get_object_from_dbcheck_condition_on_object。这将提高可读性,避免错误,并帮助检测这些错误(如果它们在某个时刻出现)。


关于“模拟导入的对象”。您可能正在尝试使用一个库来模拟一个对象,该库适用于比您的情况更高级的情况。这些库为您提供了一系列围绕测试环境的开箱即用方法,您可能不需要这些方法。从表面上看,您只想用模拟数据填充对象,和/或与模拟的 db_connection 实例交互。所以...

为了填充,我会简化:您知道要测试的条件,并且要检查给定对象的结果是否是预期的结果。只需为自己构建一个test_object_provider.py返回已知案例的true|false. 没有必要让事情变得更复杂。

要使用假 MongoDB 连接,您可以尝试使用mongomock。(尽管理想情况下您可以在单独的测试中使用真实实例来测试 mongo)。