首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >pytest和and解析:代码在使用中,但测试失败

pytest和and解析:代码在使用中,但测试失败
EN

Stack Overflow用户
提问于 2020-01-15 11:28:10
回答 2查看 1.2K关注 0票数 1

我想在我正在编写的代码中添加一些命令行参数,当我包含了argparse内容时,测试就会失败。

下面是基类的精简版本:

代码语言:javascript
复制
import argparse
import sys


class PreProcessor:

    def parse_args(self, args):
        parser = argparse.ArgumentParser(description='Arguments for PreProcessor scripts.')
        parser.add_argument('-i', '--ignore-pid', help='If the script is already running, it will not re-run. This over-rides that.', action="store_true")
        parser.add_argument('-v', '--verbose', type=int, choices=[0,1,2,3], default=1, help='Be noisy when running [0 is completely silent, 3 is debug-level. defaults to 1].')
        return parser.parse_args()

    def __init__(
        self,
        code,
    ):
        if not code:
            raise ValueError("A code must be defined")
        self.code = code

        # These two lines
        self.args = self.parse_args(sys.argv)
        print(f"type: {type(self.args)}, data: {self.args}")

……下面是它的测试文件:

代码语言:javascript
复制
import pytest
from .example import PreProcessor


def test_base_initialisation():
    foo = PreProcessor(code="foo")
    assert foo.code == "foo"

因此,我得到的错误是:

代码语言:javascript
复制
platform linux -- Python 3.6.9, pytest-3.3.2, py-1.5.2, pluggy-0.6.0 -- /usr/bin/python3
cachedir: .cache
rootdir: /home/kiz/development/FindingStudySpaces/preprocessors, inifile: pytest.ini
plugins: cov-2.5.1
collected 1 item                                                                                                                                                                                                                                                       
preprocessors/test_example.py::test_base_initialisation FAILED                     [100%]

 generated xml file: /home/kiz/development/FindingStudySpaces/preprocessors/pytest-results.xml 

----------- coverage: platform linux, python 3.6.9-final-0 -----------
Name                             Stmts   Miss  Cover
----------------------------------------------------
preprocessors/__init__.py            0      0   100%
preprocessors/example.py            14      2    86%
preprocessors/preprocessors.py     140    140     0%
----------------------------------------------------
TOTAL                              154    142     8%
Coverage HTML written to dir htmlcov

======================================== FAILURES ========================================
________________________________ test_base_initialisation ________________________________

self = ArgumentParser(prog='pytest-3', usage=None, description='Arguments for PreProcessor scripts.', formatter_class=<class 'argparse.HelpFormatter'>, conflict_handler='error', add_help=True)
action = _StoreAction(option_strings=['-v', '--verbose'], dest='verbose', nargs=None, const=None, default=1, type=<class 'int'>...es=[0, 1, 2, 3], help='Be noisy when running [0 is completely silent, 3 is debug-level. defaults to 1].', metavar=None)
arg_string = 'preprocessors/test_example.py'

    def _get_value(self, action, arg_string):
        type_func = self._registry_get('type', action.type, action.type)
        if not callable(type_func):
            msg = _('%r is not callable')
            raise ArgumentError(action, msg % type_func)
    
        # convert the value to the appropriate type
        try:
>           result = type_func(arg_string)
E           ValueError: invalid literal for int() with base 10: 'preprocessors/test_example.py'
         ... <snip loads of stuff> ...
                 # TypeErrors or ValueErrors also indicate errors
        except (TypeError, ValueError):
            name = getattr(action.type, '__name__', repr(action.type))
            args = {'type': name, 'value': arg_string}
            msg = _('invalid %(type)s value: %(value)r')
>           raise ArgumentError(action, msg % args)
E           argparse.ArgumentError: argument -v/--verbose: invalid int value: 'preprocessors/test_example.py'
         ... <snip loads more stuff> ...

我尝试过在sys.argv[1:]方法中传递init --没有什么不同。

如果我注释掉对argparse的调用(也就是其中写着# These two lines的行),那么我就可以传递..。

我真的不想在每个测试方法中添加一个模拟/补丁程序,而不是在活动代码中添加一些子句来测试def parse_args(self, args)是否已经被测试例程调用了。

……我的google发现了一些关于测试参数的讨论--传递(这很好)--但是我找不到argparse在这个级别上失败的任何地方。

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2020-01-17 11:53:45

我感谢这两位..。这才是真正对我起作用的。

__init__sys.argv[0]中查找pytest (诚实地说,它也应该查找unittestnode ),并将空列表传递给an解析器函数,如果这样做的话:

代码语言:javascript
复制
import argparse
import re
import sys

class PreProcessor:

def parse_args(self, args):
    parser = argparse.ArgumentParser(description='Arguments for PreProcessor scripts.')
    parser.add_argument('-i', '--ignore-pid', help='If the script is already running, it will not re-run. This over-rides that.', action="store_true")
    parser.add_argument('-v', '--verbose', type=int, choices=[0,1,2,3], default=1, help='Be noisy when running [0 is completely silent, 3 is debug-level. defaults to 1].')
    return parser.parse_args(args)
   
def __init__(
    self,
    code,
):
    if not code:
        raise ValueError("A code must be defined")
    self.code = code

    if re.search('pytest', sys.argv[0]):
        self.args = self.parse_args([])
    else:
        self.args = self.parse_args(sys.argv[1:])

现在,在我的测试中,我可以根据需要patch sys对象:

代码语言:javascript
复制
import pytest
import re
import sys

from unittest.mock import patch

from .example import PreProcessor


def test_base_initialisation():
    foo = PreProcessor(code="foo")
    assert foo.code == "foo"

def test_known_command_line_options(capsys):
    foo = PreProcessor(code="foo")
    test_args = ["fake", "-h"]
    with patch.object(sys, 'argv', test_args):
        with pytest.raises(SystemExit):
            foo.parse_args(sys.argv)
            captured = capsys.readouterr()
            assert re.match(captured, "usage: fake [-h] [-i] [-v {0,1,2,3}]")
            assert re.search(captured, "Arguments for PreProcessor scripts")

    test_args = ["fake", "--help"]
    with patch.object(sys, 'argv', test_args):
        with pytest.raises(SystemExit):
            foo.parse_args(sys.argv)
            captured = capsys.readouterr()
            assert re.match(captured, "usage: fake [-h] [-i] [-v {0,1,2,3}]")
            assert re.search(captured, "Arguments for PreProcessor scripts")

def test_unknown_command_line_options(capsys):
    foo = PreProcessor(code="foo")
    test_args = ["fake", "-a"]
    with patch.object(sys, 'argv', test_args):
        with pytest.raises(SystemExit):
            foo.parse_args(sys.argv)
            captured = capsys.readouterr()
            assert re.match(captured, "usage: fake [-h] [-i] [-v {0,1,2,3}]")
            assert re.search(captured, "unrecognized arguments: -a")

此外,作为参考,and解析中的帮助文本如下:

代码语言:javascript
复制
$> python3 labmon.py -h 
usage: labmon.py [-h] [-i] [-v {0,1,2,3}]

Arguments for PreProcessor scripts.

optional arguments:
  -h, --help            show this help message and exit
  -i, --ignore-pid      If the script is already running, it will not re-run.
                        This over-rides that.
  -v {0,1,2,3}, --verbose {0,1,2,3}
                        Be noisy when running [0 is completely silent, 3 is
                        debug-level. defaults to 1].

代码语言:javascript
复制
$> python3 labmon.py -a  
usage: labmon.py [-h] [-i] [-v {0,1,2,3}]
labmon.py: error: unrecognized arguments: -a
票数 1
EN

Stack Overflow用户

发布于 2020-01-15 18:04:56

这一行:

代码语言:javascript
复制
        return parser.parse_args()

应该是

代码语言:javascript
复制
        return parser.parse_args(args)

否则,parser.parse_args默认为sys.argv[1:],这可能不是您想要的。

另外,传递给它的sys.argv是调用pytest的值--您可能希望将它设置为对程序有意义的东西。

你有两种选择

  1. monkeypatch sys.argv:

代码语言:javascript
复制
from unittest import mock

def test():
    with mock.patch.object(sys, 'argv', ['yourprog', 'args', 'here']):
        ...

  1. 依赖项注入您的参数并通过您的程序传递它们:

代码语言:javascript
复制
class C:
    def __init__(self, code, args=None):
        ...
        self.parse_args(args)

    def parse_args(self, args=None):
        ...
        return parser.parse_args(args)

代码语言:javascript
复制
def test():
    thing = C(..., args=['args', 'here'])
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/59750480

复制
相关文章

相似问题

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