在 pytest 中模拟模块导入 [英] Mocking a module import in pytest

查看:61
本文介绍了在 pytest 中模拟模块导入的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I am writing a pytest plugin that should test software that's designed to work inside a set of specific environments.

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

The software I'm writing is run inside a bigger framework, which makes certain Python modules available only when running my Python software inside the framework.

为了测试我的软件,我需要模拟"或伪造整个模块(实际上,相当多).我需要以某种类似的方式实现它的功能,但我的问题是我应该如何使用 py.test 插件使这个假 Python 模块可用于我的软件代码?

In order to test my software, I'm required to "mock" or fake an entire module (actually, quite a few). I'll need to implement its functionality in some kind of similar-looking way, but my question is how should I make this fake Python module available to my software's code, using a py.test plugin?

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

For example, let's assume I have the following code in one of my source files:

import fwlib

def fw_sum(a, b):
    return fwlib.sum(a, b)

但是,fwlib 模块仅由我运行软件的框架提供,我无法在其中进行测试.

However, the fwlib module is only made available by the framework I run my software from, and I cannot test inside it.

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

How would I make sure, from within a pytest plugin, that a module named fwlib is already defined in sys.modules? Granted, I'll need to implement fwlib.sum myself. I'm looking for recommendations on how to do just that.

推荐答案

pytest 为这个用例提供了一个装置:monkeypatch.syspath_prepend.

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

You may prepend a path to sys.path list of import locations. Write a fake fwlib.py and include it in your tests, appending the directory as necessary. Like the other test modules, it needn't be included with the distribution.

在自己玩这个之后,我实际上无法弄清楚如何让夹具从库代码中正确地模拟模块级导入.到测试运行时,库代码已经导入,再打补丁已经来不及了.

After playing with this myself, I couldn't actually figure out how to get the fixture to mock module level imports correctly from the library code. By the time the tests run, the library code was already imported and then it is too late to patch.

但是,我可以提供一个不同的解决方案:您可以从 conftest.py 中注入名称,首先导入.被测代码中的后续导入语句将仅重用 sys.modules 中已经存在的对象.

However, I can offer a different solution that works: you may inject the name from within conftest.py, which gets imported first. The subsequent import statement within the code under test will just re-use the object already present in 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

这篇关于在 pytest 中模拟模块导入的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆