美文网首页Pytest教程
Pytest官方教程-13-Fixture方法及测试用例的参数化

Pytest官方教程-13-Fixture方法及测试用例的参数化

作者: 韩志超 | 来源:发表于2019-04-23 07:46 被阅读29次

目录:

  1. 安装及入门
  2. 使用和调用方法
  3. 原有TestSuite使用方法
  4. 断言的编写和报告
  5. Pytest fixtures:清晰 模块化 易扩展
  6. 使用Marks标记测试用例
  7. Monkeypatching/对模块和环境进行Mock
  8. 使用tmp目录和文件
  9. 捕获stdout及stderr输出
  10. 捕获警告信息
  11. 模块及测试文件中集成doctest测试
  12. skip及xfail: 处理不能成功的测试用例
  13. Fixture方法及测试用例的参数化
  14. 缓存: 使用跨执行状态
  15. unittest.TestCase支持
  16. 运行Nose用例
  17. 经典xUnit风格的setup/teardown
  18. 安装和使用插件
  19. 插件编写
  20. 编写钩子(hook)方法
  21. 运行日志
  22. API参考
    1. 方法(Functions)
    2. 标记(Marks)
    3. 钩子(Hooks)
    4. 装置(Fixtures)
    5. 对象(Objects)
    6. 特殊变量(Special Variables)
    7. 环境变量(Environment Variables)
    8. 配置选项(Configuration Options)
  23. 优质集成实践
  24. 片状测试
  25. Pytest导入机制及sys.path/PYTHONPATH
  26. 配置选项
  27. 示例及自定义技巧
  28. Bash自动补全设置

Fixture方法及测试用例的参数化

pytest在多个级别启用测试参数化:

@pytest.mark.parametrize:参数化测试函数

2.2版中的新功能。

版本2.4中的更改:一些改进。

内置的pytest.mark.parametrize装饰器支持测试函数的参数的参数化。以下是测试函数的典型示例,该函数实现检查某个输入是否导致预期输出:

# content of test_expectation.py
import pytest

@pytest.mark.parametrize("test_input,expected", [("3+5", 8), ("2+4", 6), ("6*9", 42)])
def test_eval(test_input, expected):
    assert eval(test_input) == expected

这里,@parametrize装饰器定义了三个不同的(test_input,expected) 元组,以便test_eval函数依次使用它们运行三次:

$ pytest
=========================== test session starts ============================
platform linux -- Python 3.x.y, pytest-4.x.y, py-1.x.y, pluggy-0.x.y
cachedir: $PYTHON_PREFIX/.pytest_cache
rootdir: $REGENDOC_TMPDIR
collected 3 items

test_expectation.py ..F                                              [100%]

================================= FAILURES =================================
____________________________ test_eval[6*9-42] _____________________________

test_input = '6*9', expected = 42

 @pytest.mark.parametrize("test_input,expected", [("3+5", 8), ("2+4", 6), ("6*9", 42)])
 def test_eval(test_input, expected):
>       assert eval(test_input) == expected
E       AssertionError: assert 54 == 42
E        +  where 54 = eval('6*9')

test_expectation.py:6: AssertionError
==================== 1 failed, 2 passed in 0.12 seconds ====================

注意

默认情况下,pytest会转义unicode字符串中用于参数化的任何非ascii字符,因为它有几个缺点。但是,如果你想在参数化中使用unicode字符串并在终端中按原样(非转义)查看它们,请在以下位置使用此选项pytest.ini

[pytest]
disable_test_id_escaping_and_forfeit_all_rights_to_community_support = True

但请记住,这可能会导致不必要的副作用甚至是错误,具体取决于所使用的操作系统和当前安装的插件,因此使用它需要你自担风险。

如本例所示,只有一对输入/输出值无法通过简单的测试方法。和通常的测试函数参数一样,你可以在traceback中看到inputoutput值。

请注意,你还可以在类或模块上使用参数化标记(请参阅使用属性标记测试函数),这将使用参数集调用多个函数。

也可以在参数化中标记单个测试实例,例如使用内置mark.xfail

# content of test_expectation.py
import pytest

@pytest.mark.parametrize(
    "test_input,expected",
    [("3+5", 8), ("2+4", 6), pytest.param("6*9", 42, marks=pytest.mark.xfail)],
)
def test_eval(test_input, expected):
    assert eval(test_input) == expected

我们运行这个:

$ pytest
=========================== test session starts ============================
platform linux -- Python 3.x.y, pytest-4.x.y, py-1.x.y, pluggy-0.x.y
cachedir: $PYTHON_PREFIX/.pytest_cache
rootdir: $REGENDOC_TMPDIR
collected 3 items

test_expectation.py ..x                                              [100%]

=================== 2 passed, 1 xfailed in 0.12 seconds ====================

之前导致失败的一个参数集现在显示为“xfailed(预期失败)”测试。

如果提供的值parametrize导致空列表 - 例如,如果它们是由某个函数动态生成的 - 则pytest的行为由该empty_parameter_set_mark选项定义。

要获得多个参数化参数的所有组合,你可以堆叠 parametrize装饰器:

import pytest

@pytest.mark.parametrize("x", [0, 1])
@pytest.mark.parametrize("y", [2, 3])
def test_foo(x, y):
    pass

这将运行与设定参数的测试x=0/y=2x=1/y=2x=0/y=3,并x=1/y=3在装饰的秩序排气参数。

基本的pytest_generate_tests例子

有时你可能希望实现自己的参数化方案或实现一些动力来确定Fixture的参数或范围。为此,你可以使用pytest_generate_tests在收集测试函数时调用的钩子。通过传入的 metafunc对象,你可以检查请求的测试上下文,最重要的是,你可以调用metafunc.parametrize()以引起参数化。

例如,假设我们想要运行一个测试,我们想通过一个新的pytest命令行选项设置字符串输入。让我们首先编写一个接受stringinputfixture函数参数的简单测试:

# content of test_strings.py

def test_valid_string(stringinput):
    assert stringinput.isalpha()

现在我们添加一个conftest.py包含命令行选项和测试函数参数化的文件:

# content of conftest.py

def pytest_addoption(parser):
    parser.addoption(
        "--stringinput",
        action="append",
        default=[],
        help="list of stringinputs to pass to test functions",
    )

def pytest_generate_tests(metafunc):
    if "stringinput" in metafunc.fixturenames:
        metafunc.parametrize("stringinput", metafunc.config.getoption("stringinput"))

如果我们现在传递两个stringinput值,我们的测试将运行两次:

$ pytest -q --stringinput="hello" --stringinput="world" test_strings.py
..                                                                   [100%]
2 passed in 0.12 seconds

让我们运行一个stringinput导致测试失败:

$ pytest -q --stringinput="!" test_strings.py
F                                                                    [100%]
================================= FAILURES =================================
___________________________ test_valid_string[!] ___________________________

stringinput = '!'

 def test_valid_string(stringinput):
>       assert stringinput.isalpha()
E       AssertionError: assert False
E        +  where False = <built-in method isalpha of str object at 0xdeadbeef>()
E        +    where <built-in method isalpha of str object at 0xdeadbeef> = '!'.isalpha

test_strings.py:4: AssertionError
1 failed in 0.12 seconds

正如所料,我们的测试方法失败

如果你没有指定stringinput,它将被跳过,因为 metafunc.parametrize()将使用空参数列表调用:

$ pytest -q -rs test_strings.py
s                                                                    [100%]
========================= short test summary info ==========================
SKIPPED [1] test_strings.py: got empty parameter set ['stringinput'], function test_valid_string at $REGENDOC_TMPDIR/test_strings.py:2
1 skipped in 0.12 seconds

请注意,metafunc.parametrize使用不同的参数集多次调用时,这些集合中的所有参数名称都不能重复,否则将引发错误。

更多例子

有关更多示例,你可能需要查看更多参数化示例

相关文章

网友评论

    本文标题:Pytest官方教程-13-Fixture方法及测试用例的参数化

    本文链接:https://www.haomeiwen.com/subject/yzncgqtx.html