问题
- I am writing unit tests for a Python library using pytest
- I need to specify a directory for test files to avoid automatic test file discovery, because there is a large sub-directory structure, including many files in the library containing "_test" or "test_" in the name but are not intended for pytest
- Some files in the library use argparse for specifying command-line options
- The problem is that specifying the directory for pytest as a command-line argument seems to interfere with using command line options for argparse
To give an example, I have a file in the root directory called script_with_args.py
as follows:
import argparse
def parse_args():
parser = argparse.ArgumentParser(description="description")
parser.add_argument("--a", type=int, default=3)
parser.add_argument("--b", type=int, default=5)
return parser.parse_args()
I also have a folder called tests
in the root directory, containing a test-file called test_file.py
:
import script_with_args
def test_script_func():
args = script_with_args.parse_args()
assert args.a == 3
If I call python -m pytest
from the command line, the test passes fine. If I specify the test directory from the command line with python -m pytest tests
, the following error is returned:
============================= test session starts =============================
platform win32 -- Python 3.6.5, pytest-3.5.1, py-1.5.3, pluggy-0.6.0
rootdir: C:\Users\Jake\CBAS\pytest-tests, inifile:
plugins: remotedata-0.2.1, openfiles-0.3.0, doctestplus-0.1.3, arraydiff-0.2
collected 1 item
tests\test_file.py F [100%]
================================== FAILURES ===================================
______________________________ test_script_func _______________________________
def test_script_func():
# a = 1
# b = 2
> args = script_with_args.parse_args()
tests\test_file.py:13:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
script_with_args.py:9: in parse_args
return parser.parse_args()
..\..\Anaconda3\lib\argparse.py:1733: in parse_args
self.error(msg % ' '.join(argv))
..\..\Anaconda3\lib\argparse.py:2389: in error
self.exit(2, _('%(prog)s: error: %(message)s\n') % args)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
self = ArgumentParser(prog='pytest.py', usage=None, description='description', f
ormatter_class=<class 'argparse.HelpFormatter'>, conflict_handler='error', add_h
elp=True)
status = 2, message = 'pytest.py: error: unrecognized arguments: tests\n'
def exit(self, status=0, message=None):
if message:
self._print_message(message, _sys.stderr)
> _sys.exit(status)
E SystemExit: 2
..\..\Anaconda3\lib\argparse.py:2376: SystemExit
---------------------------- Captured stderr call -----------------------------
usage: pytest.py [-h] [--a A] [--b B]
pytest.py: error: unrecognized arguments: tests
========================== 1 failed in 0.19 seconds ===========================
My question is, how do I specify the test file directory for pytest, without interfering with the command line options for argparse?
回答1:
parse_args()
without argument reads the sys.argv[1:]
list. That will include the 'tests' string.
pytests
also uses that sys.argv[1:]
with its own parser.
One way to make your parser testable is provide an optional argv
:
def parse_args(argv=None):
parser = argparse.ArgumentParser(description="description")
parser.add_argument("--a", type=int, default=3)
parser.add_argument("--b", type=int, default=5)
return parser.parse_args(argv)
Then you can test it with:
parse_args(['-a', '4'])
and use it in for real with
parse_args()
Changing the sys.argv
is also good way. But if you are going to the work of putting the parser in a function like this, you might as well give it this added flexibility.
回答2:
To add to hpaulj's answer, you can also use a library like unittest.mock to temporarily mask the value of sys.argv
. That way your parse args command will run using the "mocked" argv but the actual sys.argv
remains unchanged.
When your tests call parse_args()
they could do it like this:
with unittest.mock.patch('sys.argv', ['--a', '1', '--b', 2]):
parse_args()
来源:https://stackoverflow.com/questions/51710083/how-to-run-pytest-with-a-specified-test-directory-on-a-file-that-uses-argparse