IT TIP

Python : 하위 디렉토리의 모든 소스 파일에 대해 unittest.main ()을 실행하는 방법은 무엇입니까?

itqueen 2020. 12. 14. 21:24
반응형

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"가 자동으로 모든 unittest 파생 클래스에 대해 dirBar를 검색하고 "unittest.main ()"을 한 번 호출하도록합니다. 실제로이를 수행하는 가장 좋은 방법은 무엇입니까?

Python을 사용하여 dirBar의 모든 * .py 파일에 대해 execfile 을 호출하려고했습니다.이 파일은 첫 번째 .py 파일에 대해 한 번 실행되고 test.py 호출을 종료 한 다음 unittest.main ()을 추가하여 코드를 복제해야합니다. DRY 원칙을 위반하는 모든 소스 파일.


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\
        __init__.py
        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하기 만하면 모든 단위 테스트를 찾을 수 있습니다.

% 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
            ...
        ...

and I want all of the following to work in the obvious way and to be able to be supplied the same commandline arguments as are accepted by unittest:

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

The solution was to set up mypackage/tests/__init__.py like this:

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

and to set up mypackage/tests/__main__.py like this:

import unittest
from . import prepare_load_tests_function, __path__

load_tests = prepare_load_tests_function(__path__)
unittest.main()

and to copy and paste an empty __init__.py and the following __main__.py in each 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()

and also to add the standard if __name__ == '__main__': unittest.main() in each actual tests file.

(Works for me on Python 3.3 on Windows, ymmv.)

참고URL : https://stackoverflow.com/questions/644821/python-how-to-run-unittest-main-for-all-source-files-in-a-subdirectory

반응형