Предоставление параметров в TestCase из Suite в Python - PullRequest
8 голосов
/ 17 марта 2011

Из документации по питону (http://docs.python.org/library/unittest.html):

import unittest

class WidgetTestCase(unittest.TestCase):
    def setUp(self):
        self.widget = Widget('The widget')

    def tearDown(self):
        self.widget.dispose()
        self.widget = None

    def test_default_size(self):
        self.assertEqual(self.widget.size(), (50,50),
                         'incorrect default size')

    def test_resize(self):
        self.widget.resize(100,150)
        self.assertEqual(self.widget.size(), (100,150),
                         'wrong size after resize')

Вот как вызывать эти тестовые сценарии:

def suite():
    suite = unittest.TestSuite()
    suite.addTest(WidgetTestCase('test_default_size'))
    suite.addTest(WidgetTestCase('test_resize'))
    return suite

Можно ли вставить параметр custom_parameter в WidgetTestCase, например:

class WidgetTestCase(unittest.TestCase):
    def setUp(self,custom_parameter):
        self.widget = Widget('The widget')
        self.custom_parameter=custom_parameter

Ответы [ 5 ]

6 голосов
/ 30 августа 2011

Я только что добавил модуль test_suite

WidgetTestCase.CustomParameter="some_address"

Самые простые решения самые лучшие:)

3 голосов
/ 21 марта 2011

Это то, о чем я недавно думал.Да, это очень возможно сделать.Я назвал это сценарием тестирования , но я думаю, что параметризация может быть более точной.Я поставил доказательство концепции как суть здесь .Короче говоря, это мета класс, который позволяет вам определять сценарий и запускать тесты против него.С его помощью ваш пример может выглядеть примерно так:

class WidgetTestCase(unittest.TestCase):
    __metaclass__ = ScenarioMeta
    class widget_width(ScenerioTest):
        scenarios = [
            dict(widget_in=Widget("One Way"), expected_tuple=(50, 50)),
            dict(widget_in=Widget("Another Way"), expected_tuple=(100, 150))
        ]
        def __test__(self, widget_in, expected_tuple):
            self.assertEqual(widget_in.size, expected_tuple)

При запуске метакласс записывает 2 отдельных теста, поэтому на выходе получится что-то вроде:

$ python myscerariotest.py -v
test_widget_width_0 (__main__.widget_width) ... ok
test_widget_width_1 (__main__.widget_width) ... ok


----------------------------------------------------------------------
Ran 2 tests in 0.001s

OK

Как вы можете видеть, сценарии преобразуются в тесты во время выполнения.

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

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

Редактировать

Это уродливый хак, который я больше не поддерживаю.Реализация должна быть сделана как подкласс TestCase, а не как взломанный метакласс.Живи и учись.Еще лучшим решением было бы использование носовых генераторов .

3 голосов
/ 21 марта 2011

Я нашел способ сделать это, но это немного похоже на комок.

По сути, я добавляю в TestCase метод __init__, который определяет параметр 'default' и __str__, чтобы мы могли различать случаи:

class WidgetTestCase(unittest.TestCase):

    def __init__(self, methodName='runTest'):
        self.parameter = default_parameter
        unittest.TestCase.__init__(self, methodName)

    def __str__(self):
        ''' Override this so that we know which instance it is '''
        return "%s(%s) (%s)" % (self._testMethodName, self.currentTest, unittest._strclass(self.__class__))

Затем в suite () я перебираю параметры своего теста, заменяя параметр по умолчанию на один, специфичный для каждого теста:

def suite():
    suite = unittest.TestSuite()

    for test_parameter in test_parameters:
        loadedtests = unittest.TestLoader().loadTestsFromTestCase(WidgetTestCase)
        for t in loadedtests:
            t.parameter = test_parameter
        suite.addTests(loadedtests)

    suite.addTests(unittest.TestLoader().loadTestsFromTestCase(OtherWidgetTestCases))
    return suite

, где OtherWidgetTestCases - тесты, которые не нужно параметризировать.

Например, у меня есть куча тестов на реальных данных, к которым необходимо применить набор тестов, но у меня также есть несколько синтетических наборов данных, предназначенных для тестирования определенных крайних случаев, обычно не присутствующих в данных, Мне нужно только применить определенные тесты к ним, чтобы они получили свои собственные тесты в OtherWidgetTestCases.

0 голосов
/ 21 марта 2011

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

Вы упоминаете, что передаете адрес www - это почти наверняка не очень хорошая идея.Что произойдет, если вы попытаетесь запустить тесты на компьютере, где нет сетевого соединения?Ваши тесты должны быть:

  • Автоматически - они будут работать на всех машинах и платформах, где поддерживается ваше приложение, без вмешательства пользователя.Они не должны полагаться на внешнюю среду, чтобы пройти.Это означает (среди прочего), что полагаться на правильно настроенное подключение к Интернету - плохая идея.Вы можете обойти это, предоставив фиктивные данные.Вместо передачи URL-адреса ресурса, абстрагируйте источник данных и передайте поток данных или что-то еще.Это особенно легко в Python, так как вы можете использовать типизацию Python для представления потокового объекта (по этой причине python часто использует «файловый» объект!).

  • Тщательно - ваши юнит-тесты должны охватывать 100% кода и охватывать все возможные ситуации.Вы хотите проверить свой код на нескольких сайтах?Вместо этого протестируйте свой код со всеми возможными функциями, которые может включать сайт.Не зная больше о том, что делает ваше приложение, я не могу дать много советов по этому вопросу.

Теперь, похоже, что ваши тесты будут сильно зависеть от данных.Существует множество инструментов, которые позволяют вам определять наборы данных для модульных тестов и загружать их в тесты.Взгляните на тестовые таблицы Python, например.

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

0 голосов
/ 17 марта 2011

Я не верю, что сигнатура для setUp должна быть такой, какой ожидает unittest, на самом деле, setUp автоматически вызывается в методе run теста в качестве setUp () ... вы не сможете передатьэто если вы не переопределите команду run, чтобы передать нужную вам переменную.Но я думаю, что вы хотите, побеждает цель тестирования unit .Не пытайтесь использовать философию DRY с этим, каждый тестируемый вами модуль должен быть частью класса или даже частью функции / метода.

...