Инициализация модульного теста в PyDev?

Я тестирую модуль python в eclipse с помощью модульного тестирования PyDev. Я нажимаю правой кнопкой мыши на соответствующий файл и выбираю Run As → Python unit-test. Что касается этого плагина, у меня есть несколько вопросов:

  • Есть ли способ иметь метод setUpClass, который выполняется перед любым другим тестом в этом классе? В настоящее время я могу получить только setUp, который вызывается перед любым тестом класса
  • Есть ли способ иметь глобальную инициализацию, которая вызывается перед выполнением любого теста? Что-то вроде setUpModule, которое я также не могу запустить с помощью модульного тестирования PyDev.

Заранее благодарим за любой ответ и комментарий ^^
Черио Вольтан

Пример:

class TestClass(unittest.TestCase):

  @classmethod
  def setUpClass(self):
      print "Setup"    

  def test1(self):
      print "Test1"
  def test2(self):
      print "Test2"

Если я запустил это с помощью Run As → Python unit-test, метод setUpClass не вызывается.

Ответ 1

Это ошибка PyDev, и она исправлена ​​в версии 2.0.1.

setUpModule(), tearDownModule(), setUpClass() и tearDownClass() не выполняются в конфигурации запуска "Python unit-test" из-за ошибки в PyDev 2.0.0 и ранее. В 2.0.1 они корректно выполняются в конфигурациях "Python unit-test" и "Python Run". Я сам проверил его, чтобы проверить.

Ответ 2

ОК. Я дам этот снимок: я использую Pydev и изучаю использование "nosetests" для запуска тестов, поэтому он подходит. Мое решение - это полный хак, но, похоже, работает, когда говорит "Отладка как UnitTest" из PyDev:

print "before any tests (global) just once..."
class MyTestCase(unittest.TestCase):
   class_setup_called = False
   def __init__(self, test_name):
      unittest.TestCase.__init__(self, test_name)
      if not self.__class__.class_setup_called:
          self.setUpClass()
          self.__class__.class_setup_called = True
   @staticmethod
   def setUpClass():
      print "before first test only..."
   def setUp(self):
      print "before each test..."

К сожалению, это не сработает при использовании nosetests, но оно работает при запуске с pydev. Я предполагаю, что nosetests кодируется для создания экземпляров тестовых объектов до запуска каждого тестового метода, и в этом случае ваш метод init будет достаточным.

Я не могу сказать достаточно приятных вещей о носететах:

  • поддержка исключений и времени тесты.
  • поддержка аннотации "атрибуция".
  • интеграция с профилем, охватом и отчетами о результатах Xunit.
  • рекурсивное обнаружение и объяснение выполнения тестовых случаев.

примеры:

import unittest
@raises(TypeError)          
def test_forexceptions(self): 
    pass

@attr('benchmark')
@timed(5.0)
def test_benchmark(self):
    pass # do something real slow and run nosetests --with-profile -a benchmark

Дополнительные

При дальнейшем изучении, если вы используете носететы, то он вас охватывает, см. "http://somethingaboutorange.com/mrl/projects/nose/1.0.0/writing_tests.html".

У вас может быть:

разрывы уровня пакета: (они живут в сценариях инициализации уровня пакета)

def setup_package()
def teardown_package()

Сброс уровня модуля:

def setup_module()
def teardown_module()

уровень класса:

class MyTestCase(unittest.TestCase):
    @classmethod
    def setup_class(cls): pass
    @classmethod
    def teardown_class(cls): pass

и уровень тестового метода:

class MyTestCase(unittest.TestCase):
    def setUp(self): pass
    def tearDown(cls): pass

Мне нравится использовать имена "setup_", поскольку он красиво определяет точки входа в нос. Я проверил эту работу хорошо, когда запускался из nosetests через командную строку. Но они не бегут от Pydev "бегут как unit test...". Потенциальное решение может заключаться в написании плагина pydev, который использует нос для запуска тестов... возможно, у кого-то есть один? Вы можете комбинировать свой хак с носом, называя общие функции модуля, чтобы выполнять фактическую работу. В идеале наш init() был бы осведомлен о запуске из Pydev.

Ответ 3

Изменить: сводка

Выполняя тестовый пример с помощью отладчика, похоже, что это ограничение для тестового бегуна PyDev, не поддерживающего setUpClass(), по крайней мере, не с 1.6.5, которое я использую.

Возможно, это будет исправлено в версии 2.0 PyDev, но в то же время я думаю, что нам нужно придерживаться вместо __init__(), а предлагает CarlS.

Подробнее

В классе PyDev 1.6.5 PyDevTestSuite используется:

def run(self, result):
    for index, test in enumerate(self._tests):
        if result.shouldStop:
            break
        test(result)

        # Let the memory be released! 
        self._tests[index] = None

    return result

который очень похож на TestSuite.run() в python 2.6, тогда как TestSuite.run() в python 2.7.1 unittest делает больше:

def run(self, result, debug=False):
    topLevel = False
    if getattr(result, '_testRunEntered', False) is False:
        result._testRunEntered = topLevel = True

    for test in self:
        if result.shouldStop:
            break

        if _isnotsuite(test):
            self._tearDownPreviousClass(test, result)
            self._handleModuleFixture(test, result)
            self._handleClassSetUp(test, result)
            result._previousTestClass = test.__class__

            if (getattr(test.__class__, '_classSetupFailed', False) or
                getattr(result, '_moduleSetUpFailed', False)):
                continue

        if not debug:
            test(result)
        else:
            test.debug()

    if topLevel:
        self._tearDownPreviousClass(None, result)
        self._handleModuleTearDown(result)
    return result

Старый ответ

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

Если вы установите флажок Window > Preferences > PyDev > Interpreter - Python и посмотрите, какой Python Interpretter используется, вы вполне можете обнаружить, что это pre v2.7, где, если я правильно помню, был введен setUpClass.

Ссылка на новую версию python, и я подозреваю, что ваши тесты будут работать так, как есть.

Ответ 4

Вместо использования unittest.main(), который автоматически проходит все ваши тестовые классы и отдельные тесты, вы можете загружать тесты из каждого класса отдельно и выполнять их по своему усмотрению, в том числе перед каждым классом тестировать необходимые инициализации. Вы можете предшествовать всему этому с некоторой глобальной инициализацией. См. Пример ниже:

import unittest

class MyTestClass1(unittest.TestCase):

    def setUp(self):
         pass

    @classmethod
    def setUpClass(cls):
        pass

    def test1(self):
         pass

    # lots of tests

class MyTestClass2(unittest.TestCase):

    def setUp(self):
         pass

    @classmethod
    def setUpClass(cls):
        pass

    def test1(self):
         pass

    # another whole lot of tests


if __name__=="__main__":
    # add your global initialization code here
    global_initialization()

    # MyTestClass1 initialization:
    MyTestClass1.setUpClass() # python 2.7 only

    suite = unittest.TestLoader().loadTestsFromTestCase(MyTestClass1)
    unittest.TextTestRunner().run(suite)

    # MyTestClass1 initialization:
    MyTestClass2.setUpClass() # python 2.7 only

    suite = unittest.TestLoader().loadTestsFromTestCase(MyTestClass2)
    unittest.TextTestRunner().run(suite)

В документации unittest приведены некоторые другие примеры подобного использования, которые могут быть полезны.

Изменить: Неизвестно мне до этого момента, кажется, что у Python 2.7 есть setUpClass(), (должен быть метод класса, следовательно, декоратор), который, кажется, делает то, что вам нужно, Однако это не относится к Python 2.6, и вы должны предоставить свои собственные процедуры инициализации.