如何将固定装置传递给 pytest.mark.parameterize?

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

我正在尝试将三个不同的固定装置传递给我的

pytest.mark.parameterize
装饰器,如下所示:

@pytest.mark.parametrize("credentials, return_code", [
    (user1, 200),
    #(user2, 200),
    #(user3, 401)
])
def test_login():
    assert True
# Actual test uses response.return_code == return_code

但是,我收到一条错误消息:

NameError: name 'user1' is not defined

但这并不正确,我已经在

conftest.py
中定义了它:

user1_info = [('user1', 'password')]
@pytest.fixture(params=user1_info)
def user1(request):
    return request.param

如果我将测试更改为如下所示,则夹具可以工作:

def test_login(user1):
    assert True
# Actual test uses response.return_code == return_code

问题是,如果我这样做,我必须编写三个单独的测试,一个用于每个固定装置,一个用于每个 status_code 检查。如果我可以使用

parameterize
,我可以使用一个函数并检查用户/预期返回代码。

如何利用我的固定装置作为

pytest.mark.parameterize
装饰器的一部分?

python pytest
4个回答
26
投票

要将灯具作为参数化参数传递,请将它们作为字符串引用并使用关键字参数

indirect=['arg_name', ...]

然后使用参数名称

credentials
return_code
作为测试函数的参数。

@pytest.mark.parametrize(
    "credentials, return_code",
    [
        ("user1", 200),
        ("user2", 200),
        ("user3", 401),
    ],
    # Only the `credentials` parameter is a reference to the
    # fixture. The `return_code` should be passed as is.
    indirect=["credentials"],
)
def test_login(credentials, return_code):
    return True

可以在这里找到 pytest 的

parametrize
魔法与
indirect
的文档: https://docs.pytest.org/en/stable/example/parametrize.html#apply-indirect-on-pspecial-arguments


4
投票

据我所知,你不能。有一些解决方法:

1:放弃参数化

def test_login():
    for user, return_code in [
      (User("user1", ...), 200),
      (User("user2", ...), 200),
      (User("user3", ...), 401),
    ]:
        # test user
        pass

def test_login(user1, user2, user3):
    for user, return_code in [
      (user1, 200),
      (user2, 200),
      (user3, 401),
    ]:
        # test user
        pass

优点:简单
缺点:如果第一个测试失败,后面的测试就不会运行。错误消息也没有显示哪个测试用例失败了。

2:使用索引或名称进行参数化

@pytest.mark.parametrize('idx', [0,1,2])
def test_login(idx):
    user, return_code = [
      (User("user1", ...), 200),
      (User("user2", ...), 200),
      (User("user3", ...), 401),
    ][idx]
        # test user
        pass

(或使用

user1
user2
user3
灯具的等效物)

Pro:pytest 可以识别单独的测试
缺点:无用的索引/名称

3:使用间接参数化夹具

@pytest.mark.fixture
def user_and_code(request):
    if request.param == "user1":
        return User("user1", ...), 200
    elif request.param == "user2":
        return User("user2", ...), 200
    elif request.param == "user3":
        return User("user3", ...), 401

@pytest.mark.parametrize('user_and_code', ['user1', 'user2', 'user3'], indirect=True)
def test_login(user_and_code):
    user, return_code = user_and_code

    # test user
    pass

或者

@pytest.mark.fixture
def user_and_code(request, user1, user2, user3):
    return [
        (user1, 200),
        (user2, 200),
        (user3, 401),
    ][request.param]

@pytest.mark.parametrize('user_and_code', [0,1,2], indirect=True)
def test_login(user_and_code):
    user, return_code = user_and_code

    # test user
    pass

Pro:测试代码干净,夹具可以在其他测试中重用
缺点:更复杂

根据文档,间接参数化是为了在测试收集期间跳过昂贵的设置,而不是让夹具可用于参数,正如您所看到的,这效果不太好。

上述每个选项中都有一些可以混合和匹配的选择,例如实例化所有用户或使用 if/else 仅实例化您需要的内容,使用

user1
等固定装置或创建内联用户、使用名称或索引等。这些示例仅显示一些替代方案。


1
投票

pytest-cases 库 允许您对装置进行参数化。一个有效的例子:

import pytest_cases

@pytest_cases.fixture()
def one():
    return 1

@pytest_cases.fixture()
def two():
    return 2

@pytest_cases.parametrize("number", (one, two))
def test_it(number):
    assert number in [1, 2]

0
投票

您可能会遇到两种情况:

1.我有一个静态夹具,我想将其传递到参数化测试中

有了这个,您只需将固定装置作为测试函数中的最后一个参数传递即可:

import pytest 

@pytest.fixture
def myfixture():
    return 'world'


@pytest.mark.parametrize('hello', ['Hello', 'HELLO'])
def test_world(hello, myfixture):
    output = hello.lower() + myfixture 
    assert output == 'helloworld'

2.我有一个应该与名称匹配的动态装置

通过

request
夹具并使用
getfixturevalue
:

查找您想要的夹具
import pytest 

@pytest.fixture
def a():
    return 'a'

@pytest.fixture
def b():
    return 'b'


@pytest.mark.parametrize('fixture_name', ['a', 'b'])
def test_fixture_lookup(fixture_name, request):
    output = request.getfixturevalue(fixture_name)
    assert fixture_name == output
© www.soinside.com 2019 - 2024. All rights reserved.