Python: как запустить unittest.main () для всех исходных файлов в подкаталоге?

Я разрабатываю модуль Python с несколькими исходными файлами, каждый из которых имеет собственный тестовый класс, полученный из unittest прямо в источнике. Рассмотрим структуру каталогов:

dirFoo\ test.py dirBar\ __init__.py Foo.py Bar.py 

Чтобы проверить Foo.py или Bar.py, я бы добавил это в конце исходных файлов Foo.py и Bar.py:

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

И запустите Python на любом источнике, т. Е.

 $ python Foo.py ........... ---------------------------------------------------------------------- Ran 11 tests in 2.314s OK 

В идеале я бы «test.py» автоматически искал dirBar для любых производных классов unittest и сделал один вызов «unittest.main ()». Каков наилучший способ сделать это на практике?

Я попытался использовать Python для вызова execfile для каждого * .py-файла в dirBar, который запускается один раз для первого .py-файла, который найден и выходит из вызывающего test.py, а затем я должен дублировать свой код, добавив unittest.main () в каждый исходный файл, который нарушает принципы СУХОЙ.

6 Solutions collect form web for “Python: как запустить unittest.main () для всех исходных файлов в подкаталоге?”

Начиная с Python 2.7, обнаружение теста автоматизировано в пакете unittest. Из документов :

Unittest поддерживает простое обнаружение тестов. Чтобы быть совместимым с обнаружением теста, все тестовые файлы должны быть модулями или пакетами, импортируемыми из каталога верхнего уровня проекта (это означает, что их имена должны быть действительными идентификаторами).

Открытие теста выполняется в TestLoader.discover() , но также может использоваться из командной строки. Основное использование командной строки:

 cd project_directory python -m unittest discover 

По умолчанию он ищет пакеты с именем test*.py , но это можно изменить, чтобы вы могли использовать что-то вроде

 python -m unittest discover --pattern=*.py 

Вместо сценария test.py.

Вот мой тестовый код обнаружения, который, похоже, выполняет эту работу. Я хотел удостовериться, что могу легко продлить тесты без необходимости перечислять их в любом из задействованных файлов, но также не записывать все тесты в одном файле Übertest.

Таким образом, структура

 myTests.py testDir\ __init__.py testA.py testB.py 

myTest.py выглядит так:

 import unittest if __name__ == '__main__': testsuite = unittest.TestLoader().discover('.') unittest.TextTestRunner(verbosity=1).run(testsuite) 

Я считаю, что это самое простое решение для написания нескольких тестовых примеров в одном каталоге. Для решения требуется Python 2.7 или Python 3.

Я знал, что есть очевидное решение:

 dirFoo\ __init__.py test.py dirBar\ Foo.py Bar.py 

Содержание dirFoo / test.py

 from dirBar import * import unittest if __name__ == "__main__": unittest.main() 

Запустите тесты:

 $ python test.py ........... ---------------------------------------------------------------------- Ran 11 tests in 2.305s OK 

Извините за глупый вопрос.

Вы должны попробовать нос . Это библиотека, которая помогает создавать тесты и интегрируется с unittest или doctest . Все, что вам нужно сделать, это запустить nosetests и он найдет для вас все ваши unittests.

 % nosetests # finds all tests in all subdirectories % nosetests tests/ # find all tests in the tests directory 

Я придумал фрагмент, который может делать то, что вы хотите. Он идет по пути, который вы предоставляете для поиска пакетов / модулей Python, и накапливает набор тестовых наборов из этих модулей, который затем выполняет все сразу.

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

 import logging import os import unittest MODULE_EXTENSIONS = set('.py .pyc .pyo'.split()) def unit_test_extractor(tup, path, filenames): """Pull ``unittest.TestSuite``s from modules in path if the path represents a valid Python package. Accumulate results in `tup[1]`. """ package_path, suites = tup logging.debug('Path: %s', path) logging.debug('Filenames: %s', filenames) relpath = os.path.relpath(path, package_path) relpath_pieces = relpath.split(os.sep) if relpath_pieces[0] == '.': # Base directory. relpath_pieces.pop(0) # Otherwise, screws up module name. elif not any(os.path.exists(os.path.join(path, '__init__' + ext)) for ext in MODULE_EXTENSIONS): return # Not a package directory and not the base directory, reject. logging.info('Base: %s', '.'.join(relpath_pieces)) for filename in filenames: base, ext = os.path.splitext(filename) if ext not in MODULE_EXTENSIONS: # Not a Python module. continue logging.info('Module: %s', base) module_name = '.'.join(relpath_pieces + [base]) logging.info('Importing from %s', module_name) module = __import__(module_name) module_suites = unittest.defaultTestLoader.loadTestsFromModule(module) logging.info('Got suites: %s', module_suites) suites += module_suites def get_test_suites(path): """:return: Iterable of suites for the packages/modules present under :param:`path`. """ logging.info('Base path: %s', package_path) suites = [] os.path.walk(package_path, unit_test_extractor, (package_path, suites)) logging.info('Got suites: %s', suites) return suites if __name__ == '__main__': logging.basicConfig(level=logging.WARN) package_path = os.path.dirname(os.path.abspath(__file__)) suites = get_test_suites(package_path) for suite in suites: unittest.TextTestRunner(verbosity=2).run(suite) 

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

 mypackage/ tests/ test_category_1/ tests_1a.py tests_1b.py ... test_category_2/ tests_2a.py tests_2b.py ... ... 

и я хочу, чтобы все из следующего работало очевидным образом и чтобы были предоставлены те же аргументы командной строки, которые приняты unittest:

 python -m mypackage.tests python -m mypackage.tests.test_category_1 python -m mypackage.tests.test_category_1.tests_1a 

Решение состояло в том, чтобы настроить mypackage/tests/__init__.py следующим образом:

 import unittest def prepare_load_tests_function (the__path__): test_suite = unittest.TestLoader().discover(the__path__[0]) def load_tests (_a, _b, _c): return test_suite return load_tests 

и настроить mypackage/tests/__main__.py вот так:

 import unittest from . import prepare_load_tests_function, __path__ load_tests = prepare_load_tests_function(__path__) unittest.main() 

и скопировать и вставить пустой __init__.py и следующий __main__.py в каждый mypackage/tests/test_category_n/ :

 import unittest from .. import prepare_load_tests_function from . import __path__ load_tests = prepare_load_tests_function(__path__) unittest.main() 

а также добавить стандарт, if __name__ == '__main__': unittest.main() в каждом файле фактических тестов.

(Работает для меня на Python 3.3 на Windows, ymmv.)

  • Как я могу протестировать программы PySpark?
  • Тестирование загрузки файлов с помощью Flask и Python 3
  • Как запустить Tox с Travis-CI
  • насмешливое соединение сокета в Python
  • Python mock builtin 'open' в классе, используя два разных файла
  • Запустите Python unittest, чтобы при печати ничего не печаталось, только AssertionError ()
  • Импортировать произвольно-названный файл в виде Python-модуля без создания файла байт-кода
  • Python unittest - setUpClass () дает мне проблемы - почему я не могу так наследовать?
  • Python - лучший язык программирования в мире.