#python #mocking #pytest
Вопрос:
Я использую pytest-mock, но исключение создается из кода mock.patch, я проверил, что та же ошибка возникает, если я использую синтаксис @mock.patch
декоратора.
MRE (убедитесь, что у вас установлены pytest и pytest-макет, не нужно ничего импортировать):
def test_image(mocker):
mocker.patch("PIL.Image.save")
Теперь запустите pytest в этом модуле.
Ошибка:
E AttributeError: <module 'PIL.Image' from 'c:\users\...\site-packages\PIL\Image.py'> does not have the attribute 'save'
Я ясно вижу, что Image.py содержит функцию с именем save, но функции не считаются атрибутами? Я никогда не слышал, чтобы это слово использовалось для обозначения содержимого модуля.
Ответ №1:
save
является методом экземпляра PIL.Image.Image
класса, а не PIL.Image
модуля.
Вы должны реализовать патч следующим образом:
def test_image(mocker):
mocker.patch("PIL.Image.Image.save")
Если вам нужно сделать утверждения о том, что save
метод вызывается в Image
экземпляре, вам нужно имя, привязанное к макету.
Вы можете реализовать это, издеваясь над Image
классом и привязывая Mock
экземпляр к его save
методу . Например,
def test_image(mocker):
# prepare
klass = mocker.patch("PIL.Image.Image")
instance = klass.return_value
instance.save = mocker.Mock()
# act
# Do operation that invokes save method on `Image` instance
# test
instance.save.assert_called()
Комментарии:
1. Я совершенно упустил из виду, что это был метод, а не простая функция, спасибо. Одна вещь, в которой я все еще немного смущен, — это то, как я теперь ссылаюсь на исправленный метод в утверждениях. ПИЛ. Изображение. Image.save.assert_not_called (), кажется, работает, но это означает, что мне нужно импортировать PIL в мой тестовый модуль, что кажется немного странным, так как мне не нужен был этот импорт, чтобы исправить его.
2. Я обновил свой ответ, чтобы привести пример того, как вы могли бы реализовать это и сохранить свою тестовую реализацию свободной от ненужного импорта.
3. Еще раз спасибо, я действительно смог упростить ваш пример и просто назначить имя, чтобы
mocker.patch("PIL.Image.Image.save")
затем утверждать это. Это помогло мне, так как оно одновременно короче и позволяет избежать исправления всего класса, которое нарушило бы другую часть теста.