Подтвердить что ты не робот

Переопределение Python mock patch decorator

У меня есть класс Python TestCase, где все тестовые методы, кроме одного, должны исправлять объект одинаково. Другой метод требует другого поведения от одного и того же объекта. Я использую mock, поэтому я сделал:

@mock.patch('method_to_patch', mock.Mock(return_value=1))
class Tests(TestCase):

    @mock.patch('method_to_patch', mock.Mock(return_value=2))
    def test_override(self):
         (....)

Но это не работает. Когда test_override запущен, он по-прежнему вызывает исправленное поведение от декоратора класса.

После многого отладки я узнал, что во время сборки TestSuite, @patch вокруг test_override вызывается перед тем, что находится вокруг Tests, а так как mock применяет патчи по порядку, декоратор класса переопределяет декоратор метода.

Правильно ли этот порядок? Я ожидал обратное, и я не уверен, как переопределить исправление... Может быть, с выражением with?

4b9b3361

Ответ 1

Хорошо, оказывается, что хороший ночной сон и холодный душ заставили меня переосмыслить всю проблему. Я все еще очень новичок в концепции насмешек, поэтому он все еще не совсем потоплен.

Дело в том, что нет необходимости переопределять патч для издевающегося объекта. Это насмешливый объект, и это означает, что я могу заставить его сделать что угодно. Поэтому моя первая попытка:

@mock.patch('method_to_patch', mock.Mock(return_value=1))
class Tests(TestCase):

    def test_override(self):
         method_to_patch.return_value = 2
         (....)

Это сработало, но имело побочный эффект изменения возвращаемого значения для всех следующих тестов. Итак, я попробовал:

@mock.patch('method_to_patch', mock.Mock(return_value=1))
class Tests(TestCase):

    def test_override(self):
         method_to_patch.return_value = 2
         (....)
         method_to_patch.return_value = 1

И это сработало как шарм. Но, похоже, слишком много кода. Итак, я пошел по пути управления контекстом, например:

@mock.patch('method_to_patch', mock.Mock(return_value=1))
class Tests(TestCase):

    def test_override(self):
         with mock.patch('method_to_patch', mock.Mock(return_value=2):
             (....)

Я думаю, что это кажется более ясным и более кратким.

О порядке, в котором применяются декораторы patch, это фактически правильный порядок. Так же, как штабелированные декораторы применяются снизу вверх, предполагается, что декоратор метода должен быть вызван перед декоратором класса. Я предполагаю, что это имеет смысл, я просто ожидал противоположного поведения.

В любом случае, я надеюсь, что это поможет некоторым бедным новичкам, таким как моя в будущем.