Python 测试:模拟 ImportError

Nil*_*ner 4 python import mocking pytest

我有以下代码

try:
    from foo_fast import bar
except ImportError
    from foo import bar


def some_function(a, b):
    return bar(a, b)
Run Code Online (Sandbox Code Playgroud)

我现在想测试foo_fast可以导入和不能导入的两种情况。

使用pytest和pytest-mock,我自然想把这两种情况封装在一个pytest的fixture中,所以我想我会用

@pytest.fixture(params=(True, False))
def use_fast(request, mock):

    if not request.param:
        mock.patch("foo_fast.bar", side_effect=ImportError)

    return request.param


def test_foo(use_fast):
    assert some_function(1, 2)
Run Code Online (Sandbox Code Playgroud)

但是,似乎 import 语句在测试开始之前只运行一次,所以我无法模拟ImportError.

如何嘲笑这些ImportError案例?

pec*_*est 7

模拟库是可能的:

def test_import_error(self):
    with mock.patch.dict('sys.modules', {'foo_fast.bar': None}):
        # your tests with foo.bar
Run Code Online (Sandbox Code Playgroud)

在这种情况下from foo_fast import bar将引发ImportError.


Nil*_*ner 4

您可以使用monkeypatch.setitem()来设置sys.modules['foo_fast'] = None

@pytest.fixture(params=(True, False))
def use_fast(request, monkeypatch):
    if not request.param:
        monkeypatch.setitem(sys.modules, 'foo_fast', None)
    return request.param


def test_foo(use_fast):
    assert some_function(1, 2)
Run Code Online (Sandbox Code Playgroud)

请注意,在 Python 2 中

import foo_fast
Run Code Online (Sandbox Code Playgroud)

然后会产生一个ImportError,而在​​Python 3中它会产生一个ModuleNotFoundError(它是 的子类ImportError,因此try...catch块可以保持不变)