首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >使用ClickArguments SystemExit: 0时,pytest抛出异常

使用ClickArguments SystemExit: 0时,pytest抛出异常
EN

Stack Overflow用户
提问于 2022-08-22 10:01:51
回答 1查看 70关注 0票数 2

我正在尝试为python脚本运行一个测试用例。当我在python脚本方法中不使用Click装饰器和参数时,测试用例是成功的。

但是当我使用它时,它给了SystemExit: 0

commands.py:

代码语言:javascript
复制
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:

代码语言:javascript
复制
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))

当我运行测试用例时:

代码语言:javascript
复制
pytest -rA tests/test_commands.py

然后,测试失败的有:

代码语言:javascript
复制
FAILED tests/test_commands.py::test_foo_list - SystemExit: 0

全部产出如下:

代码语言:javascript
复制
============================= 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 ===============================
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2022-08-22 10:09:47

不要直接运行click命令;它们在运行时会触发sys.exit(0),这是结束命令行工具的正常和正确的方式,但在尝试测试命令时却不太有用。

相反,使用follow the chapter并使用CliRunner() object运行命令:

代码语言:javascript
复制
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;单击命令不应该真正返回任何内容,因为它们通常通过终端或通过与文件系统的交互来与用户通信,等等:

代码语言:javascript
复制
________________________________ 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测试输出。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/73443338

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档