Инициализация модульного теста в 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, и вы должны предоставить свои собственные процедуры инициализации.