Python 在pytest中模拟模块导入

Python 在pytest中模拟模块导入,python,pytest,Python,Pytest,我正在编写一个pytest插件,它应该测试设计用于在一组特定环境中工作的软件 我正在编写的软件是在一个更大的框架内运行的,这使得某些Python模块只有在框架内运行我的Python软件时才可用 为了测试我的软件,我需要“模拟”或伪造整个模块(实际上,相当多)。我需要以类似的方式实现它的功能,但我的问题是,我应该如何使用py.test插件将这个伪Python模块提供给我的软件代码 例如,假设我的一个源文件中有以下代码: import fwlib def fw_sum(a, b): ret

我正在编写一个pytest插件,它应该测试设计用于在一组特定环境中工作的软件

我正在编写的软件是在一个更大的框架内运行的,这使得某些Python模块只有在框架内运行我的Python软件时才可用

为了测试我的软件,我需要“模拟”或伪造整个模块(实际上,相当多)。我需要以类似的方式实现它的功能,但我的问题是,我应该如何使用py.test插件将这个伪Python模块提供给我的软件代码

例如,假设我的一个源文件中有以下代码:

import fwlib

def fw_sum(a, b):
    return fwlib.sum(a, b)
但是,
fwlib
模块仅由我运行软件的框架提供,我无法在其中进行测试

如何从pytest插件中确保名为
fwlib
的模块已在
sys.modules
中定义?当然,我需要自己实现
fwlib.sum
。我正在寻找关于如何做到这一点的建议。

pytest为这个用例提供了一个夹具:

您可以在导入位置列表的
sys.path
前面添加路径。编写一个假的
fwlib.py
,并将其包含在测试中,根据需要附加目录。与其他测试模块一样,它不需要包含在发行版中

在我自己玩过这个之后,我实际上无法弄清楚如何从库代码中正确地获得fixture到mock模块级导入。测试运行时,库代码已经导入,现在修补已经太迟了

但是,我可以提供另一种有效的解决方案:您可以从
conftest.py
中插入名称。被测代码中的后续import语句将重新使用已存在于
sys.modules
中的对象

包结构:

$ tree .
.
├── conftest.py
├── lib
│   └── my_lib.py
└── tests
    └── test_my_lib.py

2 directories, 3 files
文件内容:

# conftest.py
import sys

def fwlib_sum(a, b):
    return a + b

module = type(sys)('fwlib')
module.sum = fwlib_sum
sys.modules['fwlib'] = module
库文件:

# lib/my_lib.py
import fwlib

def fw_sum(a, b):
    return fwlib.sum(a, b)
测试文件:

# lib/test_my_lib.py
import my_lib

def test_sum():
    assert my_lib.fw_sum(1, 2) == 3

这太棒了,谢谢你!您能否澄清最后一句话,关于是否需要将其包含在发行版中?您可能有一个子目录
/tests/
,在创建发行版时,该目录未被
setup.py
文件打包。您可以创建例如
/tests/mocks/fwlib.py
,可以在测试运行期间导入,但它不随库分发。啊,我明白了。我将等待其他答案的到来(尽管不太可能),并很快接受你的建议。再次感谢!当导入类似于“从导入”时,有人知道如何做到这一点吗?@Neosapien同样的方法仍然有效。插入
sys.modules
名称。