Динамическое добавление методов тестирования с использованием декоратора
В последние несколько месяцев я с большим успехом использую ДДТ для параметризации своих тестов. Теперь моя проблема в том, что я не могу ввести переменную списка в качестве источника данных. Это, похоже, сбивает с толку ДДТ, заставляя его не параметризировать мои тесты Я начал создавать свое собственное решение, но я не могу понять эту последнюю часть.
Вот что я имею в качестве декораторов -
def data(*values):
def aaa(func):
def wrapper(self, *args, **kwargs):
pass
# return func(self, *args, **kwargs)
wrapper.func_name = func.__name__ + 't'
wrapper.values = values
return wrapper
return aaa
def c(cls):
for name, method in list(cls.__dict__.items()):
if hasattr(method, 'values'):
for ticket in method.values[0]:
test_name = mk_test_name(method.func_name, ticket)
print(test_name)
setattr(cls, test_name, method(cls, ticket))
return cls
И я использую это как таковое -
@c
class IntegrationTests(APITestCase):
tickets = [1, 2, 3, 4]
@data(tickets)
def tes(self, t):
print(t)
Как я могу заставить среду тестирования Python распознавать, что я добавил через декоратор? Я знаю, что методы были добавлены, потому что выдача dir
Команда в PDB отображает их. Цель этого состоит в том, чтобы я дублировал тест (ы), которые я украшаю для каждого элемента в списке. Для тех, кто интересуется, почему wrapper()
не имеет кода, я сделал это, потому что, раскомментируя строку, вызов возврата вызывает выполнение метода, который я декорирую, без параметров, что вызывает ошибку.
В моем примере я ожидаю, что будут выполнены 4 теста с разными именами.
1 ответ
Лучшее решение - использовать функцию под-тестов unittest в python 3.4. Документация найдена здесь и используется как:
class NumbersTest(unittest.TestCase):
def test_even(self):
"""
Test that numbers between 0 and 5 are all even.
"""
for i in range(0, 6):
with self.subTest(i=i):
self.assertEqual(i % 2, 0)
Для тех, кто не может использовать Python 3.4, следующее - замена бедного человека.
class sub_test_data(object):
def __init__(self, *test_data):
self.test_data = test_data
def __call__(self, func):
func.sub_test_data = self.test_data
func.has_sub_tests = True
return func
def create_test_driver(func, *args):
def test_driver(self):
try:
func(self, *args)
except AssertionError as e:
e.args += ({"test_args": args},)
raise
return test_driver
def create_sub_tests(cls):
for attr_name, func in list(vars(cls).items()):
if getattr(func, "has_sub_tests", False):
for i, value in enumerate(func.sub_test_data):
test_name = 'test_{}_subtest{}'.format(attr_name, i)
setattr(cls, test_name, create_test_driver(func, value))
return cls
@create_sub_tests
class NumbersTest(unittest.TestCase):
tickets = [0, 1, 2, 3, 4, 5]
@sub_test_data(*tickets)
def even(self, t):
self.assertEqual(t % 2, 0)