Прямо сейчас у меня есть пакет Python (назовем его mypackage
) с кучей тестов, которые я запускаю с помощью pytest. У одной конкретной функции может быть много возможных реализаций, поэтому я использовал механизм funcarg для запуска этих тестов с эталонной реализацией.
# In mypackage/tests/conftest.py
def pytest_funcarg__Feature(request):
return mypackage.ReferenceImplementation
# In mypackage/tests/test_stuff.py
def test_something(Feature):
assert Feature(1).works
Теперь я создаю отдельный пакет Python с более сложной реализацией (fancypackage
). Можно ли запустить все тесты в mypackage
, содержащие funcarg Feature
, только с разными реализациями?
Я хотел бы избежать необходимости изменять fancypackage
, если я добавлю новые тесты в mypackage
, поэтому явный импорт не идеален. Я знаю, что могу запустить все тесты с помощью pytest.main()
, но поскольку у меня есть несколько реализаций моей функции, я не хочу вызывать pytest.main()
несколько раз. В идеале это должно выглядеть примерно так:
# In fancypackage/tests/test_impl1.py
def pytest_funcarg__Feature(request):
return fancypackage.Implementation1
## XXX: Do pytest collection on mypackage.tests, but don't run them
# In fancypackage/tests/test_impl2.py
def pytest_funcarg__Feature(request):
return fancypackage.Implementation2
## XXX: Do pytest collection on mypackage.tests, but don't run them
Затем, когда я запускаю pytest в fancypackage
, он собирает каждый из тестов mypackage.tests
дважды, по одному разу для каждой реализации функции. Я пытался сделать это с явным импортом, и, кажется, он работает нормально, но я не хочу явно импортировать все.
Бонус
Дополнительным приятным бонусом будет сбор только тех тестов, которые содержат Feature
funcarg. Это возможно?
Пример с юниттестом
Прежде чем перейти на py.test, я сделал это со стандартной библиотекой unittest
. Функция для этого следующая:
def mypackage_test_suite(Feature):
loader = unittest.TestLoader()
suite = unittest.TestSuite()
mypackage_tests = loader.discover('mypackage.tests')
for test in all_testcases(mypackage_tests):
if hasattr(test, 'Feature'):
test.Feature = Feature
suite.addTest(test)
return suite
def all_testcases(test_suite_or_case):
try:
suite = iter(test_suite_or_case)
except TypeError:
yield test_suite_or_case
else:
for test in suite:
for subtest in all_testcases(test):
yield subtest
Очевидно, что сейчас все по-другому, потому что мы имеем дело с тестовыми функциями и классами, а не только с классами, но кажется, что в py.test должен быть некоторый эквивалент, который создает набор тестов и позволяет вам проходить его.