파이썬 모듈의 argparse 부분에 대한 테스트를 어떻게 작성합니까?
argparse 라이브러리를 사용하는 Python 모듈이 있습니다. 코드베이스의 해당 섹션에 대한 테스트를 작성하려면 어떻게합니까?
코드를 리팩터링하고 파싱을 함수로 이동해야합니다.
def parse_args(args):
parser = argparse.ArgumentParser(...)
parser.add_argument...
# ...Create your parser as you like...
return parser.parse_args(args)
그런 다음 main
함수 에서 다음을 호출해야합니다.
parser = parse_args(sys.argv[1:])
( sys.argv
스크립트 이름을 나타내는 첫 번째 요소는 CLI 작업 중에 추가 스위치로 보내지 않도록 스크립트 이름이 제거됩니다.)
테스트에서 테스트하려는 인수 목록으로 파서 함수를 호출 할 수 있습니다.
def test_parser(self):
parser = parse_args(['-l', '-m'])
self.assertTrue(parser.long)
# ...and so on.
이렇게하면 파서를 테스트하기 위해 응용 프로그램 코드를 실행할 필요가 없습니다.
나중에 애플리케이션에서 파서에 옵션을 변경 및 / 또는 추가해야하는 경우 팩토리 메소드를 작성하십시오.
def create_parser():
parser = argparse.ArgumentParser(...)
parser.add_argument...
# ...Create your parser as you like...
return parser
원하는 경우 나중에 조작 할 수 있으며 테스트는 다음과 같습니다.
class ParserTest(unittest.TestCase):
def setUp(self):
self.parser = create_parser()
def test_something(self):
parsed = self.parser.parse_args(['--something', 'test'])
self.assertEqual(parsed.something, 'test')
"argparse 부분"은 약간 모호하므로이 답변은 한 부분, 즉 parse_args
방법 에 중점을 둡니다 . 이것은 명령 행과 상호 작용하고 전달 된 모든 값을 얻는 방법입니다. 기본적으로 parse_args
명령 줄에서 실제로 값을 가져올 필요가 없도록 반환 내용을 조롱 할 수 있습니다 . mock
패키지는 파이썬 버전 2.6-3.2 위해 주사위를 통해 설치 될 수 있습니다. unittest.mock
버전 3.3부터는 표준 라이브러리의 일부입니다 .
import argparse
try:
from unittest import mock # python 3.3+
except ImportError:
import mock # python 2.6-3.2
@mock.patch('argparse.ArgumentParser.parse_args',
return_value=argparse.Namespace(kwarg1=value, kwarg2=value))
def test_command(mock_args):
pass
Namespace
전달되지 않은 경우에도 모든 명령 메소드의 인수를 포함해야합니다 . 해당 인수에 값을 제공하십시오 None
. ( docs 참조 )이 스타일은 각 메소드 인수에 대해 다른 값이 전달되는 경우를 신속하게 테스트하는 데 유용합니다. Namespace
테스트에서 전체 argparse 비 의존성을 위해 조롱 하기로 선택한 경우 실제 Namespace
클래스 와 유사하게 작동하는지 확인하십시오 .
다음은 argparse 라이브러리의 첫 번째 스 니펫을 사용하는 예입니다.
# test_mock_argparse.py
import argparse
try:
from unittest import mock # python 3.3+
except ImportError:
import mock # python 2.6-3.2
def main():
parser = argparse.ArgumentParser(description='Process some integers.')
parser.add_argument('integers', metavar='N', type=int, nargs='+',
help='an integer for the accumulator')
parser.add_argument('--sum', dest='accumulate', action='store_const',
const=sum, default=max,
help='sum the integers (default: find the max)')
args = parser.parse_args()
print(args) # NOTE: this is how you would check what the kwargs are if you're unsure
return args.accumulate(args.integers)
@mock.patch('argparse.ArgumentParser.parse_args',
return_value=argparse.Namespace(accumulate=sum, integers=[1,2,3]))
def test_command(mock_args):
res = main()
assert res == 6, "1 + 2 + 3 = 6"
if __name__ == "__main__":
print(main())
귀하의 확인 main()
기능 테이크 argv
오히려 것보다도 인수로를 읽기 sys.argv
가 기본적으로 것 같은 :
# mymodule.py
import argparse
import sys
def main(args):
parser = argparse.ArgumentParser()
parser.add_argument('-a')
process(**vars(parser.parse_args(args)))
return 0
def process(a=None):
pass
if __name__ == "__main__":
sys.exit(main(sys.argv[1:]))
그런 다음 정상적으로 테스트 할 수 있습니다.
import mock
from mymodule import main
@mock.patch('mymodule.process')
def test_main(process):
main([])
process.assert_call_once_with(a=None)
@mock.patch('foo.process')
def test_main_a(process):
main(['-a', '1'])
process.assert_call_once_with(a='1')
- 를 사용하여 인수 목록을 채우고을
sys.argv.append()
호출 한 후parse()
결과를 확인하고 반복하십시오. - Call from a batch/bash file with your flags and a dump args flag.
- Put all your argument parsing in a separate file and in the
if __name__ == "__main__":
call parse and dump/evaluate the results then test this from a batch/bash file.
I did not want to modify the original serving script so I just mocked out the sys.argv
part in argparse.
from unittest.mock import patch
with patch('argparse._sys.argv', ['python', 'serve.py']):
... # your test code here
This breaks if argparse implementation changes but enough for a quick test script. Sensibility is much more important than specificity in test scripts anyways.
A simple way of testing a parser is:
parser = ...
parser.add_argument('-a',type=int)
...
argv = '-a 1 foo'.split() # or ['-a','1','foo']
args = parser.parse_args(argv)
assert(args.a == 1)
...
Another way is to modify sys.argv
, and call args = parser.parse_args()
There are lots of examples of testing argparse
in lib/test/test_argparse.py
When passing results from argparse.ArgumentParser.parse_args
to a function, I sometimes use a namedtuple
to mock arguments for testing.
import unittest
from collections import namedtuple
from my_module import main
class TestMyModule(TestCase):
args_tuple = namedtuple('args', 'arg1 arg2 arg3 arg4')
def test_arg1(self):
args = TestMyModule.args_tuple("age > 85", None, None, None)
res = main(args)
assert res == ["55289-0524", "00591-3496"], 'arg1 failed'
def test_arg2(self):
args = TestMyModule.args_tuple(None, [42, 69], None, None)
res = main(args)
assert res == [], 'arg2 failed'
if __name__ == '__main__':
unittest.main()
parse_args
throws a SystemExit
and prints to stderr, you can catch both of these:
import contextlib
import io
import sys
@contextlib.contextmanager
def captured_output():
new_out, new_err = io.StringIO(), io.StringIO()
old_out, old_err = sys.stdout, sys.stderr
try:
sys.stdout, sys.stderr = new_out, new_err
yield sys.stdout, sys.stderr
finally:
sys.stdout, sys.stderr = old_out, old_err
def validate_args(args):
with captured_output() as (out, err):
try:
parser.parse_args(args)
return True
except SystemExit as e:
return False
You inspect stderr (using err.seek(0); err.read()
but generally that granularity isn't required.
Now you can use assertTrue
or whichever testing you like:
assertTrue(validate_args(["-l", "-m"]))
Alternatively you might like to catch and rethrow a different error (instead of SystemExit
):
def validate_args(args):
with captured_output() as (out, err):
try:
return parser.parse_args(args)
except SystemExit as e:
err.seek(0)
raise argparse.ArgumentError(err.read())
I found that the easiest way, for me at least, was just to check sys.argv[0] so see if python was ran as python -m unittest
and not parse anything if that was the case.
import sys
import argparse
parser = argparse.ArgumentParser()
parser.add_argument('--outdir', help='Directory to output to', \
default='out')
parser.add_argument('--file', help='Input file', \
default='section')
parser.add_argument('--word', help='Word to look up')
if sys.argv[0] == 'python -m unittest':
args = parser.parse_args([])
else:
args = parser.parse_args()
'programing tip' 카테고리의 다른 글
MySql에서 아포스트로피 ( ')를 피하는 방법? (0) | 2020.07.02 |
---|---|
Gulp.js 작업, src로 돌아 갑니까? (0) | 2020.07.02 |
에뮬레이터에서 Google Play 서비스 업데이트 (0) | 2020.07.02 |
이미 행에있는 내용을 완료하기 위해 bash 기록 완료를 어떻게 변경합니까? (0) | 2020.07.02 |
HTML (0) | 2020.07.02 |