Различное поведение @patch между Python 2.7 и 3.6 (с использованием макета)

@patch, похоже, не ведет себя так же, как в версиях 2.7 и 3.6.

Вот моя структура проекта:

project/
    foo.py
    bar.py
    lol.py
tests/
    test_project.py

foo.py:

class Foo:
    pass

bar.py (импортирует Foo):

from project.foo import Foo

class Bar:
    def __init__(self):
        f = Foo()

lol.py (импортирует Bar):

from bar import Bar

class Lol:
    def __init__(self):
        b = Bar()

Поскольку bar.py импортирует Foo с помощью from project.foo import Foo, я исправляю bar.Foo (согласно документации где патчить):

test_bar.py:

from project import lol
from project import bar

@patch('bar.Foo')  # Works in 3.6, fails with 2.7
def test_lol(mock_Foo):
    l = lol.Lol()
    mock_Foo.assert_called()

Эта установка работает правильно в Python 3.6, но не работает в 2.7 (Foo не исправляется).

Однако, если я переключу свою настройку на:

test_bar.py:

from project import lol
# from project import bar # No need to import bar anymore

@patch('project.bar.Foo')  # Works in 2.7, fails with 3.6
def test_lol(mock_Foo):
    l = lol.Lol()
    mock_Foo.assert_called()

Он работает в 2.7, но не работает в 3.6.

Каков рекомендуемый способ использования @patch для обеспечения согласованности результатов между версиями Python?

Примечание. Эта проблема появляется только при тестировании lol.py. Если я вызываю bar.py из модульного теста, я получаю стабильные результаты, используя вторую установку @patch('cookie_test.bar.Foo'), и она работает как в 2.7, так и в 3.6.

Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
4
0
496
1

Ответы 1

Я не могу воспроизвести разницу, используя 2.7 и 3.6 при добавлении файлов __init__.py в ваш каталог project и изменении импорта Bar в lol.py:

from project.bar import Bar

В любом случае вам не нужно импортировать bar в свой тест - mock позаботится о поиске bar, проанализировав строку, переданную декоратору mock.

Я подозреваю, что ошибка, которую вы видите, связана с тем, что Python 3 использует абсолютный импорт (https://www.python.org/dev/peps/pep-0328/)

Другие вопросы по теме