我正在尝试为python脚本运行一个测试用例。当我在python脚本方法中不使用Click装饰器和参数时,测试用例是成功的。
但是当我使用它时,它给了SystemExit: 0。
commands.py:
import sys
import click
@click.command()
@click.argument('bar_info', nargs=-1)
def get_all_foos(bar_info):
print("bars_to_retain --> {}".format(bar_info[1]))
print("bars_prefix --> {}".format(bar_info[0]))
# do something with bar_info
return "result"test/test_Commands.py:
import sys
import pytest
import commands
from click.testing import CliRunner
def test_foo_list():
response = commands.get_all_foos(["ctm", "10"])
print("response is --> {}".format(response))当我运行测试用例时:
pytest -rA tests/test_commands.py然后,测试失败的有:
FAILED tests/test_commands.py::test_foo_list - SystemExit: 0全部产出如下:
============================= test session starts ==============================
platform darwin -- Python 3.10.3, pytest-7.1.2, pluggy-1.0.0
rootdir: ...
collected 1 item
tests/test_commands.py F [100%]
=================================== FAILURES ===================================
________________________________ test_foo_list _________________________________
self = <Command get-all-foos>, args = [], prog_name = 'pytest'
complete_var = None, standalone_mode = True, windows_expand_args = True
extra = {}, ctx = <click.core.Context object at 0x107585d20>, rv = 'result'
def main(
self,
args: t.Optional[t.Sequence[str]] = None,
prog_name: t.Optional[str] = None,
complete_var: t.Optional[str] = None,
standalone_mode: bool = True,
windows_expand_args: bool = True,
**extra: t.Any,
) -> t.Any:
"""This is the way to invoke a script with all the bells and
whistles as a command line application. This will always terminate
the application after a call. If this is not wanted, ``SystemExit``
needs to be caught.
This method is also available by directly calling the instance of
a :class:`Command`.
:param args: the arguments that should be used for parsing. If not
provided, ``sys.argv[1:]`` is used.
:param prog_name: the program name that should be used. By default
the program name is constructed by taking the file
name from ``sys.argv[0]``.
:param complete_var: the environment variable that controls the
bash completion support. The default is
``"_<prog_name>_COMPLETE"`` with prog_name in
uppercase.
:param standalone_mode: the default behavior is to invoke the script
in standalone mode. Click will then
handle exceptions and convert them into
error messages and the function will never
return but shut down the interpreter. If
this is set to `False` they will be
propagated to the caller and the return
value of this function is the return value
of :meth:`invoke`.
:param windows_expand_args: Expand glob patterns, user dir, and
env vars in command line args on Windows.
:param extra: extra keyword arguments are forwarded to the context
constructor. See :class:`Context` for more information.
.. versionchanged:: 8.0.1
Added the ``windows_expand_args`` parameter to allow
disabling command line arg expansion on Windows.
.. versionchanged:: 8.0
When taking arguments from ``sys.argv`` on Windows, glob
patterns, user dir, and env vars are expanded.
.. versionchanged:: 3.0
Added the ``standalone_mode`` parameter.
"""
if args is None:
args = sys.argv[1:]
if os.name == "nt" and windows_expand_args:
args = _expand_args(args)
else:
args = list(args)
if prog_name is None:
prog_name = _detect_program_name()
# Process shell completion requests and exit early.
self._main_shell_completion(extra, prog_name, complete_var)
try:
try:
with self.make_context(prog_name, args, **extra) as ctx:
rv = self.invoke(ctx)
if not standalone_mode:
return rv
# it's not safe to `ctx.exit(rv)` here!
# note that `rv` may actually contain data like "1" which
# has obvious effects
# more subtle case: `rv=[None, None]` can come out of
# chained commands which all returned `None` -- so it's not
# even always obvious that `rv` indicates success/failure
# by its truthiness/falsiness
> ctx.exit()
lib/python3.10/site-packages/click/core.py:1065:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
self = <click.core.Context object at 0x107585d20>, code = 0
def exit(self, code: int = 0) -> "te.NoReturn":
"""Exits the application with a given exit code."""
> raise Exit(code)
E click.exceptions.Exit: 0
lib/python3.10/site-packages/click/core.py:687: Exit
During handling of the above exception, another exception occurred:
def test_foo_list():
> response = commands.get_all_foos(["ctm", "10"])
tests/test_commands.py:9:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
lib/python3.10/site-packages/click/core.py:1130: in __call__
return self.main(*args, **kwargs)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
self = <Command get-all-foos>, args = [], prog_name = 'pytest'
complete_var = None, standalone_mode = True, windows_expand_args = True
extra = {}, ctx = <click.core.Context object at 0x107585d20>, rv = 'result'
def main(
self,
args: t.Optional[t.Sequence[str]] = None,
prog_name: t.Optional[str] = None,
complete_var: t.Optional[str] = None,
standalone_mode: bool = True,
windows_expand_args: bool = True,
**extra: t.Any,
) -> t.Any:
"""This is the way to invoke a script with all the bells and
whistles as a command line application. This will always terminate
the application after a call. If this is not wanted, ``SystemExit``
needs to be caught.
This method is also available by directly calling the instance of
a :class:`Command`.
:param args: the arguments that should be used for parsing. If not
provided, ``sys.argv[1:]`` is used.
:param prog_name: the program name that should be used. By default
the program name is constructed by taking the file
name from ``sys.argv[0]``.
:param complete_var: the environment variable that controls the
bash completion support. The default is
``"_<prog_name>_COMPLETE"`` with prog_name in
uppercase.
:param standalone_mode: the default behavior is to invoke the script
in standalone mode. Click will then
handle exceptions and convert them into
error messages and the function will never
return but shut down the interpreter. If
this is set to `False` they will be
propagated to the caller and the return
value of this function is the return value
of :meth:`invoke`.
:param windows_expand_args: Expand glob patterns, user dir, and
env vars in command line args on Windows.
:param extra: extra keyword arguments are forwarded to the context
constructor. See :class:`Context` for more information.
.. versionchanged:: 8.0.1
Added the ``windows_expand_args`` parameter to allow
disabling command line arg expansion on Windows.
.. versionchanged:: 8.0
When taking arguments from ``sys.argv`` on Windows, glob
patterns, user dir, and env vars are expanded.
.. versionchanged:: 3.0
Added the ``standalone_mode`` parameter.
"""
if args is None:
args = sys.argv[1:]
if os.name == "nt" and windows_expand_args:
args = _expand_args(args)
else:
args = list(args)
if prog_name is None:
prog_name = _detect_program_name()
# Process shell completion requests and exit early.
self._main_shell_completion(extra, prog_name, complete_var)
try:
try:
with self.make_context(prog_name, args, **extra) as ctx:
rv = self.invoke(ctx)
if not standalone_mode:
return rv
# it's not safe to `ctx.exit(rv)` here!
# note that `rv` may actually contain data like "1" which
# has obvious effects
# more subtle case: `rv=[None, None]` can come out of
# chained commands which all returned `None` -- so it's not
# even always obvious that `rv` indicates success/failure
# by its truthiness/falsiness
ctx.exit()
except (EOFError, KeyboardInterrupt):
echo(file=sys.stderr)
raise Abort() from None
except ClickException as e:
if not standalone_mode:
raise
e.show()
sys.exit(e.exit_code)
except OSError as e:
if e.errno == errno.EPIPE:
sys.stdout = t.cast(t.TextIO, PacifyFlushWrapper(sys.stdout))
sys.stderr = t.cast(t.TextIO, PacifyFlushWrapper(sys.stderr))
sys.exit(1)
else:
raise
except Exit as e:
if standalone_mode:
> sys.exit(e.exit_code)
E SystemExit: 0
lib/python3.10/site-packages/click/core.py:1083: SystemExit
----------------------------- Captured stdout call -----------------------------
bars_to_retain --> 10
bars_prefix --> ctm
=========================== short test summary info ============================
FAILED tests/test_commands.py::test_foo_list - SystemExit: 0
============================== 1 failed in 0.15s ===============================发布于 2022-08-22 10:09:47
不要直接运行click命令;它们在运行时会触发sys.exit(0),这是结束命令行工具的正常和正确的方式,但在尝试测试命令时却不太有用。
相反,使用follow the chapter并使用CliRunner() object运行命令:
from click.testing import CliRunner
# ...
def test_foo_list():
runner = CliRunner()
result = runner.invoke(commands.get_all_foos, ["ctm", "10"])
response = result.return_value请注意,我传递了一个字符串参数列表;click将将这些参数解析为正确的结构。
我在这里将result.return_value分配给response,但知道这将是None;单击命令不应该真正返回任何内容,因为它们通常通过终端或通过与文件系统的交互来与用户通信,等等:
________________________________ test_foo_list _________________________________
----------------------------- Captured stdout call -----------------------------
response is --> None
=========================== short test summary info ============================
PASSED tests/test_commands.py::test_foo_list也许您可以使用print()或click.echo()向stdout写一些东西,然后通过result.stdout测试输出。
https://stackoverflow.com/questions/73443338
复制相似问题