디렉토리에서 모든 Python 단위 테스트를 어떻게 실행합니까?
파이썬 단위 테스트가 들어있는 디렉토리가 있습니다. 각 단위 테스트 모듈의 형식은 test _ *. py 입니다. all_test.py 라는 파일을 만들려고합니다.이 파일 은 위에서 언급 한 테스트 양식으로 모든 파일을 실행하고 결과를 반환합니다. 지금까지 두 가지 방법을 시도했습니다. 둘 다 실패했습니다. 나는 두 가지 방법을 보여줄 것이며, 누군가가 실제로 이것을 올바르게 수행하는 방법을 알고 있기를 바랍니다.
첫 번째 용감한 시도를 위해 "파일에서 모든 테스트 모듈을 가져온 다음이 unittest.main()
doodad 를 호출 하면 제대로 작동합니까?"라고 생각했습니다. 글쎄, 내가 틀렸다는 것이 밝혀졌다.
import glob
import unittest
testSuite = unittest.TestSuite()
test_file_strings = glob.glob('test_*.py')
module_strings = [str[0:len(str)-3] for str in test_file_strings]
if __name__ == "__main__":
unittest.main()
이것은 효과가 없었습니다. 결과는 다음과 같습니다.
$ python all_test.py
----------------------------------------------------------------------
Ran 0 tests in 0.000s
OK
내 두 번째 시도를 위해, 그래도, 나는 아마도이 전체 테스트 작업을보다 "수동적 인"방식으로 시도 할 것입니다. 그래서 아래에서 시도했습니다.
import glob
import unittest
testSuite = unittest.TestSuite()
test_file_strings = glob.glob('test_*.py')
module_strings = [str[0:len(str)-3] for str in test_file_strings]
[__import__(str) for str in module_strings]
suites = [unittest.TestLoader().loadTestsFromName(str) for str in module_strings]
[testSuite.addTest(suite) for suite in suites]
print testSuite
result = unittest.TestResult()
testSuite.run(result)
print result
#Ok, at this point I have a result
#How do I display it as the normal unit test command line output?
if __name__ == "__main__":
unittest.main()
이것은 또한 작동하지 않았지만 너무 가깝습니다!
$ python all_test.py
<unittest.TestSuite tests=[<unittest.TestSuite tests=[<unittest.TestSuite tests=[<test_main.TestMain testMethod=test_respondes_to_get>]>]>]>
<unittest.TestResult run=1 errors=0 failures=0>
----------------------------------------------------------------------
Ran 0 tests in 0.000s
OK
나는 일종의 스위트를 가지고있는 것처럼 보이고 결과를 실행할 수 있습니다. 나는 그것이 단지 내가 가지고 있다고 말하는 것에 대해 조금 걱정하고 run=1
있습니다 run=2
. 그러나 결과를 main에 어떻게 전달하고 표시합니까? 아니면 기본적으로 어떻게 작동하게해서이 파일을 실행할 수 있고, 그렇게 할 때이 디렉토리에서 모든 단위 테스트를 실행합니까?
이를 위해 테스트 러너를 사용할 수 있습니다. 예를 들어 코 는 매우 좋습니다. 실행되면 현재 트리에서 테스트를 찾아 실행합니다.
업데이트 :
코 이전의 코드가 있습니다. 모듈 이름의 명시적인 목록을 원하지 않을 수도 있지만 나머지는 유용 할 것입니다.
testmodules = [
'cogapp.test_makefiles',
'cogapp.test_whiteutils',
'cogapp.test_cogapp',
]
suite = unittest.TestSuite()
for t in testmodules:
try:
# If the module defines a suite() function, call it to get the suite.
mod = __import__(t, globals(), locals(), ['suite'])
suitefn = getattr(mod, 'suite')
suite.addTest(suitefn())
except (ImportError, AttributeError):
# else, just load all the test cases from the module.
suite.addTest(unittest.defaultTestLoader.loadTestsFromName(t))
unittest.TextTestRunner().run(suite)
Python 2.7 이상에서는이를 위해 새 코드를 작성하거나 타사 도구를 사용할 필요가 없습니다. 명령 행을 통한 재귀 테스트 실행이 내장되어 있습니다.
python -m unittest discover <test_directory>
# or
python -m unittest discover -s <directory> -p '*_test.py'
python 2.7 또는 python 3.x unittest 문서 에서 자세한 내용을 읽을 수 있습니다 .
파이썬 3에서 다음을 사용하는 경우 unittest.TestCase
:
- 디렉토리
__init__.py
에 비어 있거나 다른 파일이 있어야 합니다 (이름을 지정 해야 합니다 ).test
test/
- 내부의 테스트 파일
test/
은 패턴과 일치합니다test_*.py
. 이들은 아래의 서브 디렉토리 안에있을 수 있으며 해당 서브 디렉토리test/
는 무엇이든 지정할 수 있습니다.
그런 다음 다음을 사용하여 모든 테스트를 실행할 수 있습니다.
python -m unittest
끝난! 100 줄 미만의 솔루션. 다른 파이썬 초보자가 이것을 찾아서 시간을 절약하기를 바랍니다.
이제 unittest : unittest.TestLoader.discover 에서 직접 가능합니다 .
import unittest
loader = unittest.TestLoader()
start_dir = 'path/to/your/test/files'
suite = loader.discover(start_dir)
runner = unittest.TextTestRunner()
runner.run(suite)
글쎄, 위의 코드 (특히 TextTestRunner
and 사용 defaultTestLoader
) 를 연구함으로써 꽤 가까워 질 수있었습니다. 결국 나는 모든 테스트 스위트를 "수동으로"추가하는 대신 단일 스위트 생성자에 전달하여 다른 문제를 해결함으로써 코드를 수정했습니다. 그래서 여기 내 해결책이 있습니다.
import glob
import unittest
test_files = glob.glob('test_*.py')
module_strings = [test_file[0:len(test_file)-3] for test_file in test_files]
suites = [unittest.defaultTestLoader.loadTestsFromName(test_file) for test_file in module_strings]
test_suite = unittest.TestSuite(suites)
test_runner = unittest.TextTestRunner().run(test_suite)
네, 아마도 코를 사용하는 것이이 일을하는 것보다 쉬울 것입니다. 그러나 그것은 요점입니다.
다양한 테스트 케이스 클래스에서 모든 테스트를 실행하고 명시 적으로 지정하려면 다음과 같이 할 수 있습니다.
from unittest import TestLoader, TextTestRunner, TestSuite
from uclid.test.test_symbols import TestSymbols
from uclid.test.test_patterns import TestPatterns
if __name__ == "__main__":
loader = TestLoader()
tests = [
loader.loadTestsFromTestCase(test)
for test in (TestSymbols, TestPatterns)
]
suite = TestSuite(tests)
runner = TextTestRunner(verbosity=2)
runner.run(suite)
어디에 uclid
내 프로젝트 및 TestSymbols
및 TestPatterns
의 서브 클래스입니다 TestCase
.
이 discover
방법 을 사용하여 load_tests
코드의 (최소한, 생각하는) 숫자 줄로이 결과를 달성했습니다.
def load_tests(loader, tests, pattern):
''' Discover and load all unit tests in all files named ``*_test.py`` in ``./src/``
'''
suite = TestSuite()
for all_test_suite in unittest.defaultTestLoader.discover('src', pattern='*_tests.py'):
for test_suite in all_test_suite:
suite.addTests(test_suite)
return suite
if __name__ == '__main__':
unittest.main()
5-5에서 실행
Ran 27 tests in 0.187s
OK
나는 다양한 접근 방식을 시도했지만 모두 결함이있는 것처럼 보이거나 코드를 작성해야합니다. 그러나 리눅스에는 확실한 패턴이 있습니다. 즉, 특정 패턴을 통해 모든 테스트를 찾은 다음 하나씩 테스트하는 것입니다.
find . -name 'Test*py' -exec python '{}' \;
가장 중요한 것은 확실히 작동합니다.
(A)의 경우 패키지 라이브러리 나 응용 프로그램, 당신은하고 싶지 않아. setuptools
당신을 위해 그것을 할 것 입니다.
이 명령을 사용하려면
unittest
함수, TestCase 클래스 또는 메소드 또는TestCase
클래스를 포함하는 모듈 또는 패키지로 프로젝트의 테스트를 테스트 스위트에 랩핑해야합니다 . 명명 된 제품군이 모듈이고 모듈에additional_tests()
기능 이있는 경우 해당 모듈 이 호출되고 결과 (이어야 함unittest.TestSuite
)가 실행될 테스트에 추가됩니다. 명명 된 제품군이 패키지 인 경우 모든 하위 모듈과 하위 패키지가 전체 테스트 제품군에 재귀 적으로 추가됩니다 .
루트 테스트 패키지가 어디에 있는지 알려주십시오.
setup(
# ...
test_suite = 'somepkg.test'
)
그리고 실행하십시오 python setup.py test
.
파일 기반 검색 discover
은 파일 가져 오기를 사용 하기 때문에 테스트 스위트에서 상대적 가져 오기를 피하지 않으면 Python 3에서 문제가 될 수 있습니다 . optional을 지원 top_level_dir
하지만 무한 재귀 오류가 발생했습니다. 따라서 패키지화되지 않은 코드에 대한 간단한 해결책은 다음을 __init__.py
테스트 패키지 에 넣는 것입니다 ( load_tests 프로토콜 참조 ).
import unittest
from . import foo, bar
def load_tests(loader, tests, pattern):
suite = unittest.TestSuite()
suite.addTests(loader.loadTestsFromModule(foo))
suite.addTests(loader.loadTestsFromModule(bar))
return suite
PyDev / LiClipse를 사용하고 실제로 GUI에서 모든 테스트를 한 번에 실행하는 방법을 찾지 못했습니다. (편집 : 루트 테스트 폴더를 마우스 오른쪽 버튼으로 클릭하고Run as -> Python unit-test
이것은 현재 해결 방법입니다.
import unittest
def load_tests(loader, tests, pattern):
return loader.discover('.')
if __name__ == '__main__':
unittest.main()
이 코드를 all
테스트 디렉토리 에있는 모듈에 넣었습니다 . LiClipse에서이 모듈을 단위 테스트로 실행하면 모든 테스트가 실행됩니다. 특정 또는 실패한 테스트 만 반복하도록 요청하면 해당 테스트 만 실행됩니다. 내 명령 줄 테스트 러너를 방해하지 않으며 무시하지 않습니다.
discover
프로젝트 설정에 따라 인수를 변경해야 할 수도 있습니다 .
Stephen Cagle 의 답변에 따라 중첩 테스트 모듈에 대한 지원을 추가했습니다.
import fnmatch
import os
import unittest
def all_test_modules(root_dir, pattern):
test_file_names = all_files_in(root_dir, pattern)
return [path_to_module(str) for str in test_file_names]
def all_files_in(root_dir, pattern):
matches = []
for root, dirnames, filenames in os.walk(root_dir):
for filename in fnmatch.filter(filenames, pattern):
matches.append(os.path.join(root, filename))
return matches
def path_to_module(py_file):
return strip_leading_dots( \
replace_slash_by_dot( \
strip_extension(py_file)))
def strip_extension(py_file):
return py_file[0:len(py_file) - len('.py')]
def replace_slash_by_dot(str):
return str.replace('\\', '.').replace('/', '.')
def strip_leading_dots(str):
while str.startswith('.'):
str = str[1:len(str)]
return str
module_names = all_test_modules('.', '*Tests.py')
suites = [unittest.defaultTestLoader.loadTestsFromName(mname) for mname
in module_names]
testSuite = unittest.TestSuite(suites)
runner = unittest.TextTestRunner(verbosity=1)
runner.run(testSuite)
이 코드 .
는 *Tests.py
파일 의 모든 하위 디렉토리를 검색 한 다음로드합니다. 각 *Tests.py
클래스에는 *Tests(unittest.TestCase)
차례로로드되어 차례로 실행되는 단일 클래스가 포함될 것으로 예상됩니다 .
이것은 디렉토리 / 모듈의 임의의 깊은 중첩에서 작동하지만 그 사이의 각 디렉토리에는 __init__.py
최소한 빈 파일이 있어야합니다. 이렇게하면 테스트에서 슬래시 (또는 백 슬래시)를 점으로 대체하여 중첩 모듈을로드 할 수 있습니다 (참조 replace_slash_by_dot
).
테스트 디스커버리는 완전한 주제 인 것처럼 보이기 때문에 디스커버리를 테스트하기위한 전용 프레임 워크가 있습니다.
자세한 내용은 여기 : https://wiki.python.org/moin/PythonTestingToolsTaxonomy
이 BASH 스크립트는 파일 시스템의 어느 디렉토리에 있든지 상관없이 파일 시스템의 모든 위치에서 python unittest 테스트 디렉토리를 실행합니다. 작업 디렉토리는 항상 해당 test
디렉토리가있는 위치입니다.
모든 테스트, 독립적 인 $ PWD
unittest Python 모듈은 ( discover -s
옵션을 사용하여 ) 어디에 지시하지 않는 한 현재 디렉토리에 민감합니다 .
이것은 ./src
또는 ./example
작업 디렉토리에 머무를 때 유용 하며 빠른 전체 단위 테스트가 필요합니다.
#!/bin/bash
this_program="$0"
dirname="`dirname $this_program`"
readlink="`readlink -e $dirname`"
python -m unittest discover -s "$readlink"/test -v
선택된 테스트, 독립 $ PWD
이 유틸리티 파일의 이름을 다음 runone.py
과 같이 사용하십시오.
runone.py <test-python-filename-minus-dot-py-fileextension>
#!/bin/bash
this_program="$0"
dirname="`dirname $this_program`"
readlink="`readlink -e $dirname`"
(cd "$dirname"/test; python -m unittest $1)
test/__init__.py
파일을 제작할 때 패키지 / 메모리 오버 헤드에 부담을 줄 필요가 없습니다 .
이것은 오래된 질문이지만 2019 년 현재 나를 위해 일한 것은 다음과 같습니다.
python -m unittest *_test.py
모든 테스트 파일은 소스 파일과 동일한 폴더에 있으며로 끝납니다 _test
.
다음은 명령 행에서 테스트를 실행하기 위한 랩퍼 를 작성 하는 방법입니다 .
#!/usr/bin/env python3
import os, sys, unittest, argparse, inspect, logging
if __name__ == '__main__':
# Parse arguments.
parser = argparse.ArgumentParser(add_help=False)
parser.add_argument("-?", "--help", action="help", help="show this help message and exit" )
parser.add_argument("-v", "--verbose", action="store_true", dest="verbose", help="increase output verbosity" )
parser.add_argument("-d", "--debug", action="store_true", dest="debug", help="show debug messages" )
parser.add_argument("-h", "--host", action="store", dest="host", help="Destination host" )
parser.add_argument("-b", "--browser", action="store", dest="browser", help="Browser driver.", choices=["Firefox", "Chrome", "IE", "Opera", "PhantomJS"] )
parser.add_argument("-r", "--reports-dir", action="store", dest="dir", help="Directory to save screenshots.", default="reports")
parser.add_argument('files', nargs='*')
args = parser.parse_args()
# Load files from the arguments.
for filename in args.files:
exec(open(filename).read())
# See: http://codereview.stackexchange.com/q/88655/15346
def make_suite(tc_class):
testloader = unittest.TestLoader()
testnames = testloader.getTestCaseNames(tc_class)
suite = unittest.TestSuite()
for name in testnames:
suite.addTest(tc_class(name, cargs=args))
return suite
# Add all tests.
alltests = unittest.TestSuite()
for name, obj in inspect.getmembers(sys.modules[__name__]):
if inspect.isclass(obj) and name.startswith("FooTest"):
alltests.addTest(make_suite(obj))
# Set-up logger
verbose = bool(os.environ.get('VERBOSE', args.verbose))
debug = bool(os.environ.get('DEBUG', args.debug))
if verbose or debug:
logging.basicConfig( stream=sys.stdout )
root = logging.getLogger()
root.setLevel(logging.INFO if verbose else logging.DEBUG)
ch = logging.StreamHandler(sys.stdout)
ch.setLevel(logging.INFO if verbose else logging.DEBUG)
ch.setFormatter(logging.Formatter('%(asctime)s %(levelname)s: %(name)s: %(message)s'))
root.addHandler(ch)
else:
logging.basicConfig(stream=sys.stderr)
# Run tests.
result = unittest.TextTestRunner(verbosity=2).run(alltests)
sys.exit(not result.wasSuccessful())
간단하게하기 위해 PEP8 이외의 코딩 표준을 변명하십시오 .
그런 다음 모든 테스트의 공통 구성 요소에 대한 BaseTest 클래스를 만들 수 있으므로 각 테스트는 다음과 같습니다.
from BaseTest import BaseTest
class FooTestPagesBasic(BaseTest):
def test_foo(self):
driver = self.driver
driver.get(self.base_url + "/")
실행하려면 간단히 명령 줄 인수의 일부로 테스트를 지정하십시오.
./run_tests.py -h http://example.com/ tests/**/*.py
참고 URL : https://stackoverflow.com/questions/1732438/how-do-i-run-all-python-unit-tests-in-a-directory
'IT' 카테고리의 다른 글
'git log'로 첫 번째 커밋을 표시하는 방법은 무엇입니까? (0) | 2020.04.01 |
---|---|
정밀도가 2 인 소수에 대한 간단한 정규식 (0) | 2020.04.01 |
점선 테두리 점 사이의 공간을 늘리는 방법 (0) | 2020.04.01 |
Xcode 8에서 파생 데이터를 어떻게 삭제합니까? (0) | 2020.04.01 |
숭고한 텍스트 2 : 빈 줄을 비우는 방법 (0) | 2020.04.01 |