Как динамически украсить класс python unittest несколькими патчами

#python #dynamic #python-unittest #python-decorators

#питон #динамический #python-unittest #питон-декораторы

Вопрос:

Функция определяется в source.py и позвонил в use_source.py. Я исправляю это с test.py вот так

source.py

 def example_function():  print("I don't want this to run")  

use_source.py

 from source import example_function  def call_example_function():  example_function()  

test.py

 import unittest from unittest.mock import patch import use_source  file_names = ["use_source.example_function"]   def fake_function():  print("I want this to run instead")   @patch(file_names[0], new=fake_function) class ExampleTest(unittest.TestCase):   def test_example(self):  use_source.call_example_function()   if __name__ == '__main__':  unittest.main()  

Однако у меня есть несколько файлов, таких как use_source.py это я хочу исправить, поэтому вот мой вопрос

Как динамически вызвать декоратора исправлений с учетом списка целей?

Я ищу что-то вроде этого

 @patch_list(file_names, new=fake_function) class ExampleTest(unittest.TestCase):  

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

 @patch(file_names[0], new=fake_function) @patch(file_names[1], new=fake_function) class ExampleTest(unittest.TestCase):  

Наконец, я ищу решение, которое только изменяет test.py

Ответ №1:

Синтаксис декоратора-это просто синтаксический сахар для приложения функций. Ты мог бы написать

 class ExampleTest(unittest.TestCase):  ...  for f in file_names:  ExampleTest = patch(f, new=fake_function)(ExampleTest)  

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

Комментарии:

1. спасибо, но с приведенным выше кодом я бы либо получил ссылку на «локальную переменную ‘ExampleTest’ перед назначением», либо не применял исправление, т. Е. «Я не хочу, чтобы это запускалось».

2. Я не вижу никакой причины для ошибки локальной переменной. Вы поместили цикл в инструкцию класса или после нее? (Это должно быть после, как показано на рисунке.)

3. да, ошибка локальной переменной была в операторе класса, но если я помещу цикл после оператора класса, исправление не будет применено

Ответ №2:

Я могу использовать декоратор, но использовать patch.start() в методе setUpClass теста

 import unittest from unittest.mock import patch import use_source  file_names = ["use_source.example_function"]   def fake_function():  print("I want this to run instead")  class ExampleTest(unittest.TestCase):   @classmethod  def setUpClass(cls):  for file_name in file_names():  patch(file_name, new=fake_function).start()   def test_example(self):  use_source.call_example_function()   if __name__ == '__main__':  unittest.main()  

Запуск python test.py дает тот же результат, что и выше, и позволяет мне исправлять большое и разнообразное количество методов!