类中的设置函数在传递参数化值时无法按预期工作

问题描述 投票:0回答:1

我不知道为什么将here提到的代码修改为以下内容不起作用?这些变量在测试内部不可访问,并且尽管范围设置为类,但在每次测试之前都会调用设置。任何指示都会非常有帮助。谢谢

#conftest.py
def pytest_addoption(parser):
    parser.addoption("--data", action="store", default="1,2 3,4 5,6", help="Data for parametrization")

def pytest_generate_tests(metafunc):
    data_str = metafunc.config.getoption("data")
    # data_list = [(1, 2), (3, 4), (5, 6)]
    data_list = [tuple(map(int, item.split(','))) for item in data_str.split()]
    # metafunc.parametrize("data", data_list, indirect=True)
    metafunc.parametrize("data", data_list, scope="class")

# @pytest.fixture(scope="class")
# def data(request):
#     return request.param

#test_code.py
import pytest
class Test1():
    @pytest.fixture(scope="class", autouse=True)
    def setup(self, data, request):
        print(data)
        [self.a, self.b] = list(data)
        self.c = self.a + self.b
        print('Test1.setup')

    def test_a(self):
        print("Test1.test_a")
        print(f'Test1.test_a - {self.a}, {self.b}, {self.c}')
        self.d = self.c * 2

    def test_b(self):
        print("Test1.test_b")
        print(f'Test1.test_b - {self.d}')

问题应该出在 pytest_generate_tests 上,因为我认为每个测试都会调用它?!

python python-3.x pytest command-line-arguments parameterization
1个回答
0
投票

您的代码的问题是在

setup()
函数中使用类范围。 setup 函数不是类方法:它是实例方法。此外,我认为使用类太复杂了。我更喜欢使用测试函数。为此,我重新设计和重新组织测试如下:

#!/usr/bin/env python3
# conftest.py

import json

import pytest


def pytest_addoption(parser: pytest.Parser):
    parser.addoption(
        "--data",
        action="store",
        default="[[1, 2], [3, 4], [5, 6]]",
        help="Data for parametrization",
    )


def pytest_generate_tests(metafunc: pytest.Metafunc):
    # Only parametrize for the 'data' fixture
    if "data" not in metafunc.fixturenames:
        return

    # Using pytest.param() gives us the option
    # to assign an ID to the test data
    data_list = [
        pytest.param(data, id=f"a={data[0]}, b={data[1]}")
        for data in json.loads(metafunc.config.getoption("data"))
    ]
    metafunc.parametrize("data", data_list, scope="session")


@pytest.fixture(scope="session")
def c_value(data):
    return sum(data)


@pytest.fixture(scope="session")
def d_value(c_value):
    return c_value * 2

# test_code.py
import logging


def test_a(data, c_value):
    logging.debug("data=%r", data)
    logging.debug("c_value=%r", c_value)


def test_b(data, c_value, d_value):
    logging.debug("data=%r", data)
    logging.debug("c_value=%r", c_value)
    logging.debug("d_value=%r", d_value)

# pyproject.toml
[tool.pytest.ini_options]
log_cli = "true"
log_level = "DEBUG"
log_format = "%(levelname)s | %(filename)s(%(lineno)d) | %(funcName)s | %(message)s"
markers = ["slow"]

输出:

$ pytest -s -v
========================================== test session starts ===========================================
platform linux -- Python 3.12.4, pytest-8.3.1, pluggy-1.5.0 -- /var/tmp/venv/sandbox/bin/python
cachedir: .pytest_cache
rootdir: /home/haiv/temp/so/pytest-parametrize-cmdline
configfile: pyproject.toml
plugins: check-2.3.1, pythonpath-0.7.3, assume-2.4.3, anyio-4.4.0
collected 6 items                                                                                        

test_code.py::test_a[a=1, b=2] 
--------------------------------------------- live log call ----------------------------------------------
DEBUG | test_code.py(6) | test_a | data=[1, 2]
DEBUG | test_code.py(7) | test_a | c_value=3
PASSED
test_code.py::test_b[a=1, b=2] 
--------------------------------------------- live log call ----------------------------------------------
DEBUG | test_code.py(11) | test_b | data=[1, 2]
DEBUG | test_code.py(12) | test_b | c_value=3
DEBUG | test_code.py(13) | test_b | d_value=6
PASSED
test_code.py::test_a[a=3, b=4] 
--------------------------------------------- live log call ----------------------------------------------
DEBUG | test_code.py(6) | test_a | data=[3, 4]
DEBUG | test_code.py(7) | test_a | c_value=7
PASSED
test_code.py::test_b[a=3, b=4] 
--------------------------------------------- live log call ----------------------------------------------
DEBUG | test_code.py(11) | test_b | data=[3, 4]
DEBUG | test_code.py(12) | test_b | c_value=7
DEBUG | test_code.py(13) | test_b | d_value=14
PASSED
test_code.py::test_a[a=5, b=6] 
--------------------------------------------- live log call ----------------------------------------------
DEBUG | test_code.py(6) | test_a | data=[5, 6]
DEBUG | test_code.py(7) | test_a | c_value=11
PASSED
test_code.py::test_b[a=5, b=6] 
--------------------------------------------- live log call ----------------------------------------------
DEBUG | test_code.py(11) | test_b | data=[5, 6]
DEBUG | test_code.py(12) | test_b | c_value=11
DEBUG | test_code.py(13) | test_b | d_value=22
PASSED

=========================================== 6 passed in 0.02s ============================================

讨论

  • 我没有自己解析数据,而是采用JSON格式,所以解析就是调用的问题
    json.loads()
  • 对于
    data_list
    ,我使用
    pytest.param()
    ,我可以命名数据,从而得到更详细的测试名称。
  • 灯具具有“会话”范围,因为数据不会改变
  • 我把所有的固定装置都放进去
    conftest.py
    所以
    test_code.py
    很干净
  • 我使用
    logging
    而不是
    print
    ,因为
    logging
    print
    提供更多功能、更多细节。此外,我可以通过编辑来控制日志输出
    pyproject.toml
© www.soinside.com 2019 - 2024. All rights reserved.