目录
  • pytest fixtures测试函数参数化
    • 一、@pytest.mark.parametrize:参数化测试函数
      • 1. 常规用法
      • 2. 在参数化中标记单个测试实例
      • 3. 多个参数化组合,笛卡尔积
    • 二、用钩子函数pytest_generate_tests example拓展
    • 总结

      pytest fixtures测试函数参数化

      Pytest会在以下几个级别启用测试参数化:

      • pytest.fixture(),可以对fixture函数进行参数化。
      • @pytest.mark.parametrize,可以在测试函数或类中定义多组参数和fixture。
      • pytest_generate_tests,可以自定义参数化方案或扩展。

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

      1. 常规用法

      对测试函数的参数进行参数化,直接使用内置的装饰器pytest.mark.parameterized即可。

      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

      从代码里可以看出,在装饰器里定义了三个不同的元组。我们把("test_input,expected", [("3+5", 8), ("2+4", 6), ("6*9", 42)])
      拆开看:

      • "test_input,expected":这个字符串里定义了2个参数,test_input和expected。
      • ("3+5", 8), ("2+4", 6), ("6*9", 42):这里3个元组,没个元组里有2个元素,依次序分别对应test_input和expected。
      • 3个元组外层的[]:列表里就是参数化具体的传参了,因为里面传了3个不同的元组,所以测试函数test_eval会分别执行3次。
      ============================= test session starts =============================
      platform win32 -- Python 3.9.4, pytest-6.2.3, py-1.10.0, pluggy-0.13.1
      rootdir: D:\PycharmProjects\wms-api\interface, configfile: pytest.inicollected 3 items
      test_module1.py ..F
      demo\test_module1.py:3 (test_eval[6*9-42])
      54 != 42
      Expected :42
      Actual   :54
       <Click to see difference>
      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_module1.py:6: AssertionError

      运行结果可以看到最后一次失败了,因为第三次运行测试函数取的参数是 ("6*9", 42),54不等于42,所以断言失败。

      2. 在参数化中标记单个测试实例

      在参数化中标记单个测试实例,比如之前提到过的mark.xfail,这个可以标记测试函数为失败。那么在参数化中,如果想让其中的某个参数运行
      的时候测试失败,就可以这样用:

      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

      运行一下:

      test_module1.py                                                       [100%]
      ======================== 2 passed, 1 xfailed in 0.05s =========================..x

      3. 多个参数化组合,笛卡尔积

      如果在测试函数上加了多个参数化装饰器,那么得到的参数组合是一个笛卡尔积:

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

      应该会组合成4组数据x=0/y=2, x=1/y=2, x=0/y=3, 和x=1/y=3,测试函数执行4次:

      test_module1.py .
      x: 0
      y: 2
      .
      x: 1
      y: 2
      .
      x: 0
      y: 3
      .
      x: 1
      y: 3
                                                           [100%]
      ============================== 4 passed in 0.01s ==============================

      二、用钩子函数pytest_generate_tests example拓展

      如果有些场景需要动态的确定参数或者fixture的使用范围,那么可以使用pytest_generate_tests这个钩子函数,该函数会在收集测试函数时候被调用。

      通过传入的metafunc对象,可以检查请求测试函数的上下文,还可以进一步的调用metafunc.parameterize()来实现参数化。

      举例,有个测试函数需要接受输入的字符串作为参数,而且通过pytest命令行获取到,那么就要编写一个获取参数的fixture函数来给测试函数调用。

      # content of test_strings.py
      def test_valid_string(stringinput):
          assert stringinput.isalpha()

      新建conftest.py文件,fixture函数写在这里:

      # 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"))

      现在用命令行方式来运行这个测试函数:

      pytest -q –stringinput="hello" –stringinput="world" test_strings.py

      会运行2次。

      D:\PycharmProjects\wms-api\interface\demo>pytest -q --stringinput="hello" --stringinput="world" test_strings.py
      ..                                                                                                                                                                     [100%]
      2 passed in 0.01s

      再换个输入参数,让测试函数失败:

      pytest -q –stringinput="!" test_strings.py

      FAILED test_strings.py::test_valid_string[!] - AssertionError: assert False1 failed in 0.04s

      如果没有字符串输入,那么测试函数它将被跳过。因为metafunc.parameterize()被调用时&#xff0c;传过去的是一个列表:

      pytest -q -rs test_strings.py

      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.12s

      注意,在调用metafunc时, 如果使用不同的参数集进行多次参数化,这些参数集上的所有参数名称都不能重复,否则将会报错。

      总结

      文中讲到的3种用法,实际应用中第一种最常见,第二种次之,至于第三种,可以作为一些用法启发,更多关于pytest fixtures测试函数参数化的资料请关注其它相关文章!

      声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。