Проверьте поведение кода, если дополнительный модуль не установлен - PullRequest
1 голос
/ 18 марта 2020

У меня есть программный пакет, packageA, который необязательно зависит от packageB. Если установлена ​​packageB, то у пользователя есть доступ к некоторым дополнительным функциям. Но отсутствие его установки не ограничивает использование packageA.

Я хочу написать модульный (или интеграционный?) Тест, который проверяет, что packageA все еще можно использовать, если packageB не установлен. .. то есть он не будет неожиданно выдавать ImportError для packagB

Тест, который я имею, написан так:

from unittest import mock
import pytest


def test_no_err_if_packageb_not_installed():
    import sys
    sys.modules['packageB'] = mock.MagicMock()
    try:
        from packageA import file_that_uses_packageb  # noqa: F401
    except NameError:
        pytest.fail("packagB dependency found at root level")

И это работает, если он называется в изоляции. Но когда он вызывается как часть пакета тестирования, этот тест всегда будет проходить. Это связано с тем, что в предыдущих тестах sys.modules уже был заполнен модулями импорта. Сначала я попытался del пакет из sys.modules, но это не сработало

Как правильно написать этот тест?

Редактировать с рабочим решение

from unittest import mock
import pytest


def test_no_err_if_packageb_not_installed():
    import sys

    # clear cached modules
    mods = list(sys.modules.keys())
    for mod in mods:
        if 'packageA' in mod or 'packageB' in mod:
            del sys.modules[mod]

    sys.modules['packageB'] = mock.MagicMock()
    try:
        from packageA import file_that_uses_packageb  # noqa: F401
    except NameError:
        pytest.fail("packagB dependency found at root level")

    del sys.modules['packageB']

1 Ответ

1 голос
/ 18 марта 2020

Взлом с sys.modules для этого есть путь к go. Проблема в том, что вы сбрасываете импорт packageB, но на самом деле, чтобы выполнить этот тест, вам также нужно сбросить импорт file_that_uses_packageb.

. В вашей тестовой настройке попробуйте del sys.modules["packageB"], sys.modules["packageA.file_that_uses_packageB"], и вы должно быть все установлено.

Не забудьте сбросить их снова в конце теста, иначе другие тесты, фактически использующие packageB, не пройдут.

(ответ, который был временно отмечен так как «дублированный» ответ не касается тех же точек - ответ говорит об использовании imp.reload, который сбрасывает и перезапускает модуль, хорошо - но не позволяет вам заменять код модуля на mocks, если это необходимо)

...