Исправление одного вхождения при вызове функции в Python Mock

Предположим, я исправляю и имитирую определенную функцию foo(), которая реализует чтение нескольких файлов. Итак, у нас есть несколько вызовов open():

def foo():
    a=open("stuff.txt")
    b=open("another_thing.txt")
    c=open("last_one.txt")

Если я сделаю mock.patch("__builtin__.open", return_value='kaboom'), первое вхождение open() будет исправлено, единственный файл чтения с именем "stuff.txt".

Что, если мне нужно исправить вторые (любые другие) вызовы open() в foo(), чтобы имитировать return_value из чтения, скажем, another_thing.txt?


person Community    schedule 19.01.2016    source источник


Ответы (2)


Поскольку вам не нравится лучший ответ (ответ Дэниела), я могу рассказать, как вы можете это сделать, с помощью side_effect:

>>> import mock
>>> with mock.patch("__builtin__.open", side_effect = ["kaboom", "more","moremore"]):
...     assert "kaboom" == open("stuff.txt")
...     assert "more" == open("another_thing.txt")
...     assert "moremore" == open("last_one.txt")

Или лучше

>>> with mock.patch("__builtin__.open", side_effect = lambda name, *args: name):
...     assert "stuff.txt" == open("stuff.txt")
...     assert "another_thing.txt" == open("another_thing.txt")
...     assert "last_one.txt" == open("last_one.txt")

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

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

person Michele d'Amico    schedule 19.01.2016
comment
Это лучший ответ на мой вопрос. Даниель хорош, но совершенно бесполезен в моих обстоятельствах. Я просто не могу изменить код, который нужно протестировать. - person ; 19.01.2016
comment
Итак, напишите свой тест, затем измените код и, наконец, измените свой тест. Этот тест будет здесь, чтобы проверить ваше поведение, но это неправильный способ сделать это, потому что он связывает ваш производственный код с вашими тестами, поэтому вы должны удалить его как можно скорее. - person Michele d'Amico; 19.01.2016
comment
Что плохого в использовании side_effects, кроме того, что я пишу тесты для исправления кода, а не наоборот? - person ; 19.01.2016
comment
side_effect не является неправильным само по себе, неправильно писать тесты, которые вводят протокол, который на самом деле не имеет значения. В первой версии side_effect вы должны позаботиться о порядке открытия файла. Если этот порядок не имеет значения, вы вводите что-то, что сделает ваш тест менее гибким. - person Michele d'Amico; 19.01.2016

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

a = open_stuff()
b = open_another_thing()
c = open_last_one()
person Daniel Roseman    schedule 19.01.2016
comment
Я рискну с побочным эффектом. Как использовать его для присвоения возвращаемых значений? - person ; 19.01.2016