【问题标题】:Argparse Unit Test with IP Address Module带有 IP 地址模块的 Argparse 单元测试
【发布时间】:2021-03-22 03:55:07
【问题描述】:

我想为以下函数编写单元测试:

#!/usr/bin/env python3

"""IPv4 validation using `ipaddress module` and argparse."""

import argparse
from ipaddress import ip_address

def parse_cli_args():
    """
    Command line parser for subnet of interest.

    Args:
      --ip 0.0.0.0

    Returns:
      String, e.g. 0.0.0.0

    """

    parser = argparse.ArgumentParser(description="IPv4 address of interest.")
    parser.add_argument("--ip", action="store", type=ip_address,\
                        required=True,\
                        help="IP address of interest, e.g. 0.0.0.0")

    args = parser.parse_args()

    return args

if __name__ == '__main__':
    args = parse_cli_args()
    print(args.ip)

按预期工作,例如:

python3 test.py --ip 192.168.1.1

192.168.1.1

python3 test.py --ip derp

用法:test.py [-h] --ip IP test.py:错误:参数--ip:无效的 ip_address 值:'derp'

python3 test.py --ip

用法:test.py [-h] --ip IP test.py: error: argument --ip: 期望一个参数

如何在单元测试中模拟这三个条件?

我尝试了一些变体:

import unittest
from unittest.mock import patch


class ParseCLIArgs(unittest.TestCase):

    """Unit tests."""

    @patch('builtins.input', return_value='192.168.1.1')
    def test_parse_cli_args_01(self, input):
        """Valid return value."""
        self.assertIsInstance(parse_cli_args(), ipaddress.IPv4Address)

if __name__ == '__main__':
    unittest.main()

没有成功。我做错了什么,我该如何解决?

编辑我更进一步:

class ParseCLIArgs(unittest.TestCase):

def setUp(self):
    self.parser = parse_cli_args()

def test_parser_cli_args(self):
    parsed = self.parser.parse_args(['--ip', '192.168.1.1'])
    self.assertIs(parsed.ip, '192.168.1.1')

if __name__ == '__main__':
    unittest.main()

失败:TypeError: isinstance() arg 2 must be a type or tuple of types。我相信这是因为该函数实际上会转换用户输入。

【问题讨论】:

  • 不详细阅读您的问题,我将进行一般性观察。测试框架作品通常有自己的解析器和命令行参数。因此,在此基础上添加您自己的论点可能会很棘手。我不建议在测试框架中包含argparse。至于你的问题,不完整。 “没有成功”是对您的问题的不充分描述。
  • 我想编写一个模拟有效用户输入的测试,例如--ip 192.168.1.1。提供的测试失败并出现以下错误:usage: test2.py [-h] --ip IP test2.py: error: the following arguments are required: --ip,表明我实际上并没有正确传递模拟。

标签: python-3.x argparse python-unittest python-mock


【解决方案1】:

要测试解析器,您需要修改 sys.argv 或提供您自己的替代品。

调用时

 args = parser.parse_args(argv)

如果argvNone(或未提供),它将解析sys.argv[1:]。这是 shell/解释器给它的列表。否则它将解析您提供的等效列表。

test_argparse.py 使用两种方法来测试解析器 - 构造自定义 sys.argv 并使用自定义 argv 调用 parse_args

要注意的另一件事是错误捕获。大多数解析错误会显示用法、错误消息然后退出。捕获该出口和 stderr 消息需要一些工作。 test_argparse 使用自定义 error 方法创建 ArgumentParser 的子类。

总而言之,对依赖于sys.argv 的代码执行unittest 并执行系统退出,可能需要比其价值更多的工作。也就是说,我不是单元测试和模拟工具方面的专家。我刚刚研究了test_argparse 文件。

【讨论】:

  • 我不清楚如何阅读test_argparse 文件。如何查看?
  • 我曾经在一个开发发行版的test 目录中找到。它可能可以在当前的github 存储库中找到,但我有一段时间没有看。这是一个复杂的文件,所以我不确定它是否值得你学习。你有没有用你的标签搜索过以前的 SO?
  • 我确实看过similar post,但我认为我的用例略有不同,因为我正在调用另一个模块来保证用户输入的准确性。我也是 SO 领域的发烧友...
  • 链接的 SO 中的答案似乎涵盖了主要问题。
【解决方案2】:

希望这可以为有类似问题的人提供很好的样本。这个测试完成了我想要它做的大部分(但不是全部)。我仍在进行单元测试以检查 Type

#!/usr/bin/env python3

"""IPv4 validation using `ipaddress module` and argparse."""

import argparse
from ipaddress import ip_address

import unittest

def parse_cli_args():
    """
    Command line parser for subnet of interest.
    Args:
      --ip 0.0.0.0
    Returns:
      String, e.g. 0.0.0.0
    """

    parser = argparse.ArgumentParser(description="IPv4 address of interest.")
    parser.add_argument("--ip", action="store",\
                        required=True,\
                        help="IP address of interest, e.g. 0.0.0.0")

    return parser

class ParseCLIArgs(unittest.TestCase):

    def setUp(self):
        self.parser = parse_cli_args()

    def test_parser_cli_args(self):
        parsed = self.parser.parse_args(['--ip', '192.168.1.1'])
        self.assertEqual(parsed.ip, '192.168.1.1')



if __name__ == '__main__':
    unittest.main()

【讨论】:

    猜你喜欢
    • 2018-09-25
    • 1970-01-01
    • 1970-01-01
    • 2019-05-28
    • 2017-01-17
    • 2023-03-06
    • 1970-01-01
    • 1970-01-01
    • 2019-11-01
    相关资源
    最近更新 更多