Как вы генерируете динамические (параметризованные) модульные тесты в Python? - PullRequest
189 голосов
/ 28 августа 2008

У меня есть какие-то тестовые данные и я хочу создать модульный тест для каждого элемента Моей первой идеей было сделать это так:

import unittest

l = [["foo", "a", "a",], ["bar", "a", "b"], ["lee", "b", "b"]]

class TestSequence(unittest.TestCase):
    def testsample(self):
        for name, a,b in l:
            print "test", name
            self.assertEqual(a,b)

if __name__ == '__main__':
    unittest.main()

Недостатком этого является то, что он обрабатывает все данные в одном тесте. Я хотел бы создать один тест для каждого элемента на лету. Есть предложения?

Ответы [ 22 ]

0 голосов
/ 26 мая 2016

Помимо использования setattr, мы можем использовать load_tests начиная с python 3.2. Пожалуйста, обратитесь к сообщению в блоге blog.livreuro.com / ru / coding / python / как генерировать обнаруживаемые юнит-тесты в python-динамически /

class Test(unittest.TestCase):
    pass

def _test(self, file_name):
    open(file_name, 'r') as f:
        self.assertEqual('test result',f.read())

def _generate_test(file_name):
    def test(self):
        _test(self, file_name)
    return test

def _generate_tests():
    for file in files:
        file_name = os.path.splitext(os.path.basename(file))[0]
        setattr(Test, 'test_%s' % file_name, _generate_test(file))

test_cases = (Test,)

def load_tests(loader, tests, pattern):
    _generate_tests()
    suite = TestSuite()
    for test_class in test_cases:
        tests = loader.loadTestsFromTestCase(test_class)
        suite.addTests(tests)
    return suite

if __name__ == '__main__':
    _generate_tests()
    unittest.main()
0 голосов
/ 22 апреля 2016

У меня были проблемы с очень специфическим стилем параметризованных тестов. Все наши тесты Selenium могут выполняться локально, но они также должны иметь возможность удаленного запуска на нескольких платформах SauceLabs. По сути, я хотел взять большое количество уже написанных тестовых случаев и параметризовать их с наименьшим количеством возможных изменений в коде. Кроме того, мне нужно было иметь возможность передавать параметры в метод setUp, чего я не видел в других решениях.

Вот что я придумала:

import inspect
import types

test_platforms = [
    {'browserName': "internet explorer", 'platform': "Windows 7", 'version': "10.0"},
    {'browserName': "internet explorer", 'platform': "Windows 7", 'version': "11.0"},
    {'browserName': "firefox", 'platform': "Linux", 'version': "43.0"},
]


def sauce_labs():
    def wrapper(cls):
        return test_on_platforms(cls)
    return wrapper


def test_on_platforms(base_class):
    for name, function in inspect.getmembers(base_class, inspect.isfunction):
        if name.startswith('test_'):
            for platform in test_platforms:
                new_name = '_'.join(list([name, ''.join(platform['browserName'].title().split()), platform['version']]))
                new_function = types.FunctionType(function.__code__, function.__globals__, new_name,
                                                  function.__defaults__, function.__closure__)
                setattr(new_function, 'platform', platform)
                setattr(base_class, new_name, new_function)
            delattr(base_class, name)

    return base_class

При этом все, что мне нужно было сделать, это добавить простой декоратор @sauce_labs () к каждому обычному старому TestCase, и теперь при их запуске они упаковываются и переписываются, так что все методы тестирования параметризуются и переименовываются. , LoginTests.test_login (self) запускается как LoginTests.test_login_internet_explorer_10.0 (self), LoginTests.test_login_internet_explorer_11.0 (self) и LoginTests.test_login_firefox_43.0 (self), и у каждого из них есть свой собственный параметр. Платформа для запуска, даже в LoginTests.setUp, что крайне важно для моей задачи, поскольку именно здесь инициализируется соединение с SauceLabs.

В любом случае, я надеюсь, что это может помочь кому-то, кто хочет сделать аналогичную «глобальную» параметризацию своих тестов!

...