2014-09-16 8 views
0

Я использую следующую функцию для добавления тестов в свои тестовые примеры.Связывание с различными методами

def add_tests(cls, args, name_builder): 
    for a in args: 
     def tb(a): 
     return lambda self: self.test_body(*a) 
     setattr(cls, name_builder(a), tb(a)) 

На данный момент я могу использовать его как это:

class TestEqual(unittest.TestCase): 
    def test_body(self, i, j): 
     self.assertNotEquals(0, i-j) 

add_tests(TestEqual, ((0,0),(1,1)), build_name_1) 

Как я могу изменить add_tests для того, чтобы сделать что-то вроде этого:

class TestRestart(unittest.TestCase): 

    def test_mode_flow(self, mode): 
     machine.set_mode(mode) 
     self.assertTrue(machine.restart()) 

    def test_gear_flow(self, gear, speed): 
     machine.set_gear(gear) 
     machine.set_speed(speed) 
     self.assertTrue(machine.restart()) 

add_tests(TestRestart, test_mode_flow, (mode.SILENT, mode.NOISY), build_name_mode) 
add_tests(TestRestart, test_gear_flow, ((1,33),(4,22)), build_name_gear) 

Другими словами, я хочу для удаления жестко запрограммированного вызова до self.test_body(*a) и вместо этого передать в качестве аргумента метод выбора.

+0

Какая версия Python? – Veedrac

ответ

1

Вы можете передать имя метода для вашей add_tests функции:

def add_tests(cls, method_name, name_builder, *args): 
    method = getattr(cls, method_name) 
    for arg in args: 
     setattr(cls, name_builder(arg), lambda self, arg=arg: method(*arg)) 

Используется как:

class TestRestart(unittest.TestCase): 
    def test_mode_flow(self, mode): 
     machine.set_mode(mode) 
     self.assertTrue(machine.restart()) 

    def test_gear_flow(self, gear, speed): 
     machine.set_gear(gear) 
     machine.set_speed(speed) 
     self.assertTrue(machine.restart()) 

add_tests(TestRestart, 'test_mode_flow', build_name_mode, mode.SILENT, mode.NOISY) 
add_tests(TestRestart, 'test_gear_flow', build_name_gear, (1,33), (4,22)) 

Альтернативой передать метод непосредственно:

def add_tests(cls, method, name_builder, *args): 
    for arg in args: 
     setattr(cls, name_builder(arg), lambda self, arg=arg: method(self, *arg)) 

И используйте его как:

add_tests(TestRestart, TestRestart.test_mode_flow, build_name_mode, mode.SILENT, mode.NOISY) 
add_tests(TestRestart, TestRestart.test_gear_flow, build_name_gear, (1,33), (4,22)) 

Другим вариантом было бы использовать декоратора:

from functools import wraps 

def add_tests(*args): 
    def decorator(method): 
     @wraps(method) 
     def wrapper(self): 
      for arg in args: 
       method(self, *arg) 
     return wrapper 
    return decorator 

и использовать его как:

class TestRestart(unittest.TestCase): 
    @add_tests(mode.SILENT, mode.NOISY) 
    def test_mode_flow(self, mode): 
     machine.set_mode(mode) 
     self.assertTrue(machine.restart()) 

    @add_tests((1, 33), (4, 22)) 
    def test_gear_flow(self, gear, speed): 
     machine.set_gear(gear) 
     machine.set_speed(speed) 
     self.assertTrue(machine.restart()) 

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

Смежные вопросы