Метапрограммирование в питоне
наткнулся на отличную статью про метапрограммирование в питоне http://habrahabr.ru/blogs/python/64359/ - всем советую :)
решил использовать - в юнит-тестах:
(навороты для того что бы передать список вариантов (набор) параметров тестируемой фукции и сгенерить класс юнит-теста с функциями, тестирующими каждая свой сет параметров)
Но! Создать пустой класс, потомок unittest.TestCase, на лету не получилось :(
(вот еще мегастатья http://www.ibm.com/developerworks/ru/library/l-pymeta/index.html)
класс создался, но не породился от unittest.TestCase... поэтому просто сделал пустой класс и испльзовал его. И теперь в сообщениях об ошибках в тест-кейсе выдается это фейковое имя:
см строку __main__.TestClass. С этим конечно тоже можно жить, но...
Возник вопрос: а можно ли изменить имя класса на лету?
Другой вопрос - не слишком ли я усложнил? ;) может есть простые решения для автоматического юнит-тестирования на основе наборов входных параметров?
решил использовать - в юнит-тестах:
class MyTestCase:
def __init__(self, test_funct, testing_param_set, test_class = None):
# тестируемая функция и набор параметров к ней
self.main_funct = test_funct
self.testing_param_set = testing_param_set
# имя тестируемой функции
self.test_funct_name = self.main_funct.__name__
# имя файла для сохранения эталонных данных
self.etalon_file_name = self.test_funct_name + '.etalon'
if test_class:
# пользователь уже создал класс - потомок unittest.TestCase - со своими функциями, юзаем его
self.test_class = test_class
else:
# юзаем пустой класс - потомок unittest.TestCase
self.test_class = TestClass
# набиваем класс тестовыми функциями
self.make_test_case()
def make_test_case_name(self, case_params):
"""
генерит уникальное имя тест-кейса для данного набора параметров, которое будет использовано в эталоне и вызове теста
"""
return self.test_funct_name + '_' + '_'.join(map(str, case_params))
def test_case_funct_factory(self, case_name, case_params):
"""
фабрика функций-тест-кейсов
"""
def funct(self_in_test):
# print etalon[case_name], main_funct(case_params)
self_in_test.assertEqual( self.main_funct(case_params), self.etalon[case_name] )
return funct
def make_test_case(self):
"""
создать функции тестирования на основе списка параметров
с помощью метапрограммирования (см. http://habrahabr.ru/blogs/python/64359/)
"""
for case_params in self.testing_param_set:
case_name = self.make_test_case_name(case_params) # имя тест-кейса
test_case_funct = self.test_case_funct_factory(case_name, case_params) # генеририм тестовую функцию
setattr(self.test_class, 'test_'+case_name, test_case_funct ) # добавляем сгенерированную функцию как метод класса
if __name__ == '__main__':
test = MyTestCase(
test_funct = getTEMarketsList,
testing_param_set = [
[None, None, 'all', 0],
[None, None, 'all', 1],
[None, None, 'inday', 0],
[None, None, 'inday', 1],
['currency', None, 'all', 0],
['stock', None, 'all', 1],
['stock', None, 'offday', 0],
],
test_class = None
)
test.load_etalon() # загружаем эталоны значений функции при данном наборе параметров
test.reinit_database( # пересоздаем таблички в тестовой БД
database='xxx',
tables = ['yyy', 'zzz']
)
test.run() # пускаем тест
(навороты для того что бы передать список вариантов (набор) параметров тестируемой фукции и сгенерить класс юнит-теста с функциями, тестирующими каждая свой сет параметров)
Но! Создать пустой класс, потомок unittest.TestCase, на лету не получилось :(
(вот еще мегастатья http://www.ibm.com/developerworks/ru/library/l-pymeta/index.html)
from new import classobj
self.test_class = classobj('MyNameClass', (unittest.TestCase, ), {})
класс создался, но не породился от unittest.TestCase... поэтому просто сделал пустой класс и испльзовал его. И теперь в сообщениях об ошибках в тест-кейсе выдается это фейковое имя:
======================================================================
FAIL: test_getTEMarketsList_currency_None_all_0 (__main__.TestClass)
----------------------------------------------------------------------
Traceback (most recent call last):
File "getTEMarketsList.py", line 62, in funct
self_in_test.assertEqual( self.main_funct(case_params), self.etalon[case_name] )
AssertionError: [['currency', 'seltttt'], ['currency', 'basket']] != [['currency', 'selt'], ['currency', 'basket']]
см строку __main__.TestClass. С этим конечно тоже можно жить, но...
Возник вопрос: а можно ли изменить имя класса на лету?
Другой вопрос - не слишком ли я усложнил? ;) может есть простые решения для автоматического юнит-тестирования на основе наборов входных параметров?
