Менеджер контекста патча pytest-mock не восстанавливает объект при выходе

Недавно мы перешли с unittest на pytest. Я столкнулся со странной проблемой при использовании mocker.patch в качестве диспетчера контекста. Рассмотрим следующий пример.

module_a.py

class MyClass:
    def value(self):
        return 10

module_b.py

import module_a
class AnotherClass:
    def get_value(self):
        return module_a.MyClass().value()

test_module_b.py

from module_b import AnotherClass
def test_main_2(mocker):
    with mocker.patch('module_a.MyClass.value', return_value=20):
        value = AnotherClass().get_value()
        assert value == 20
    value = AnotherClass().get_value()
    assert value == 10

Я ожидал бы, что после выхода из диспетчера контекста метод метода значения MyClass будет восстановлен (возвращаемое значение 10), однако тест не выполняется на втором операторе assert с ошибкой утверждения 20 != 10 Если я использую тот же тест, но заменяю mocker.patch на unittest.mock.patch, проходит. Я думал, что pytest-mock использует тот же API, что и unittest.mock, поэтому я не понимаю, почему есть разница.


person jgrant    schedule 08.10.2019    source источник


Ответы (1)


С pytest-mock разрыв выполняется при выходе из контекста фикстуры. Объект mocker.patch - это не просто псевдоним для mock.patch.

Вам не нужны контекстные менеджеры в тестовых функциях при написании тестов в стиле pytest, и фактически цель плагина pytest-mock - использовать диспетчеры контекста и декораторы функций для имитации ненужных.

Если по какой-то причине вам действительно нужен этап разборки из внутри самого теста, тогда вам нужен простой старый макет API, который также отлично работает в pytest.

from unittest.mock import patch

def test_main_2():
    with patch('module_a.MyClass.value', return_value=20):
        value = AnotherClass().get_value()
        assert value == 20
    value = AnotherClass().get_value()
    assert value == 10

Имейте в виду, что эта вложенная структура - это действительно то, чего pytest намеревается избегать, чтобы сделать ваши тесты более читаемыми, поэтому вы несколько упускаете суть, если не выполняете настройку и разборку полностью с помощью фикстур.

person wim    schedule 08.10.2019
comment
Спасибо за четкое объяснение. Я сейчас сталкиваюсь с этой проблемой, используя гипотезу + pytest (и насмехаясь). Гипотеза прекрасна, но она не работает с pytest-mock: HypothesisDeprecationWarning: test_fileaccess.py::test_readfile uses the 'mocker' fixture, which is reset between function calls but not between test cases generated by @ given (...) _ 2_ - person Mike Williamson; 17.09.2020