У меня есть функция точки входа, вызывающая ее main
на объекте, который я хотел бы оставить незащищенным, поскольку она вызывает несколько других методов объекта:
class Thing(object):
def main(self):
self.alpha()
self.bravo()
def alpha(self):
self.charlie()
def bravo(self):
raise TypeError("Requires Internet connection!")
def charlie(self):
raise Exception("Bad stuff happens here!")
Это довольно просто, чтобы смоделировать вручную:
thing = Thing()
thing.alpha = MagicMock()
thing.bravo = MagicMock()
И я могу протестировать, чтобы убедиться, что оба вызова alpha и bravo вызываются один раз, я могу установить побочные эффекты в alpha и bravo, чтобы убедиться, что они обрабатываются, и т. Д. И т. Д.
Меня беспокоит то, что определение кода изменится и кто-то добавит charlie
вызов к main
. Его не высмеивают, поэтому теперь будут ощущаться побочные эффекты (и это такие вещи, как запись в файл, подключение к базе данных, получение данных из Интернета, так что это простое исключение не будет предупреждать меня о том, что тесты сейчас плохой).
Мой план состоял в том, чтобы убедиться, что мой фиктивный объект не вызывает никаких других методов, кроме тех, которые я сказал, что он должен (или вызвать тестовое исключение). Однако если я сделаю что-то вроде этого:
MockThing = create_autospec(Thing)
thing = Thing()
thing.main()
print thing.method_calls
# [calls.main()]
Затем main
также издевается, поэтому он не вызывает никаких других методов. Как я могу издеваться над всеми методами, кроме основного? (Я бы хотел, чтобы method_calls был [calls.alpha(), calls.bravo()]
).
Изменить: для взлома ответов
Что ж, у меня есть действительно хакерское решение, но я надеюсь, что есть лучший ответ, чем этот. Обычно я повторно привязываю метод из исходного класса (Python связывает несвязанный метод)
MockThing = create_autospec(Thing)
thing = MockThing()
thing.main = Thing.ingest.__get__(thing, Thing)
thing.main()
print thing.method_calls
# [calls.alpha(), calls.bravo()]
Но должно быть более простое решение, чем использование дескрипторов функций!