Python Unittest - Мок против патча - PullRequest
0 голосов
/ 06 августа 2020
  1. В чем разница между использованием mock.Mock() и mock.patch()?

  2. Когда использовать mock.Mock() и когда использовать mock.patch()

  3. Я читал, что Mock используется для замены того, что используется в текущей области видимости, vs, patch используется для замены того, что импортировано и / или создано в другой области. Может кто-нибудь объяснить, что это значит?

  • Если мы тестируем в отдельном тестовом файле, не будет ли каждый тестируемый метод classmethod, staticmethod, intancemethod импортирован из файлов dev / production ? Означает ли это, что здесь следует использовать только патч? И если бы я должен был протестировать тот же файл, что и тестируемый код, лучше использовать mock? Это правильно?

1 Ответ

1 голос
/ 06 августа 2020

Я не совсем уверен, понял ли я ваш вопрос, но я попробую. Как описано в документации , Mock объекты (фактически MagickMock экземпляры) создаются с использованием декоратора patch:

from unittest.mock import patch

@patch('some_module.some_object')
def test_something(mocked_object):
    print(mocked_object)

Это дает что-то вроде:

<MagicMock name='some_object' id='1870192381512'>

Это эквивалентно:

def test_something():
    with patch('some_module.some_object') as mocked_object:
        print(mocked_object)

Это дает вам возможность заменить любой объект фиктивным объектом, чтобы избежать вызова фактического производственного кода и / или проверить, как исходный объект вызывается (если объект является функцией). Причина, по которой использование patch (или некоторых подобных методов) является предпочтительным, заключается в том, что это гарантирует, что исправление будет отменено после теста (или после области диспетчера контекста во втором случае), поэтому нет никаких побочных эффектов для других тестов или другой код.

Чтобы процитировать документацию:

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

Вы также можете создать объект Mock вручную и назначить его объекту - я предполагаю, что это то, что вы имею в виду в вашем вопросе. Если вы сделаете это вместо использования patch, вы должны сами сбросить предыдущее состояние. Поскольку это более подвержено ошибкам, я бы посоветовал использовать специальные методы исправления, если это возможно.

Где это не имеет значения, так это в локальных объектах и ​​других имитаторах. Мокинг локальных объектов требуется редко, но Mock экземпляров часто создаются вместе с исправлением объекта, чтобы сохранить экземпляр фиктивного объекта для последующей проверки:

@mock.patch('my_functions.MyClass')
def test_object(mock_class):
    arg1 = Mock()
    arg2 = Mock()
    do_something(arg1, arg2)

    # check that do_something creates MyClass with the given arguments 
    mock_class.assert_called_with(arg1, arg2)

В этом случае будет только случай используется в качестве аргумента фиктивного объекта, поэтому сброс не требуется.

Подводя итог:

  • patch - это удобная функция декоратора / диспетчера контекста для замены объектов фиктивными объектами (или другие объекты) и сбросить предыдущее состояние после завершения или в случае исключения
  • Mock или производные объекты создаются mock.patch, а также могут быть созданы вручную. Созданные вручную макеты обычно используются только для исправления локальных функций или других макетов, когда сброс не требуется.
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...