5

I have the following code

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


def some_function(a, b):
    return bar(a, b)

I now want to test the two cases where foo_fast could be imported and where it couldn't.

Using pytest and pytest-mock, I naturally want to encapsulate the two situations in a pytest fixture, so I thought I would use

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

However it seems the import statement is only run once before the test starts so I cannot mock the ImportError.

How does one mock these ImportError cases?

Nils Werner
  • 34,832
  • 7
  • 76
  • 98

2 Answers2

8

It is possible with the mock library:

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

In this case from foo_fast import bar will raises ImportError.

ikoverdyaev
  • 783
  • 1
  • 12
  • 17
4

You can use monkeypatch.setitem() to set 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)

Note that in Python 2

import foo_fast

will then rise an ImportError, while in Python 3 it raises a ModuleNotFoundError (which is a subclass of ImportError, so the try...catch blocks can remain unchanged)

Nils Werner
  • 34,832
  • 7
  • 76
  • 98