了解pytest fixture参数化



我有下面一段可以正常工作的代码:

import pytest
class Person:
    def __init__(self, name, age=None, height=None, lots_of_properties=None):
        self.name = name
        if age is not None:
            self.age = age
        if height is not None:
            self.height = height
        if lots_of_properties is not None:
            self.lots_of_properties["somepropertykey"] = "somepropertyvalue"
@pytest.fixture
def a_person():
    return Person("simon", 32)
def test_person_name(a_person):
    assert a_person.name == "simon"
def test_person_age(a_person):
    assert a_person.age == 32

这就是我到目前为止一直在使用fixture的方式。我创建了一个可以通过多个测试的夹具对象a_person。在上面的例子中,我不能在创建时真正指定年龄,因为a_person只定义了年龄。我怎么能传递更多的关键字参数夹具?另外,我如何修改a_person夹具,以便我也可以修改人员的姓名和年龄?我一直在谷歌周围,看起来我必须使用@pytest.mark.parametrize,但我似乎不能理解它如何适用于这种情况。基本上,我想要这样写:

@pytest.fixture
def a_person(name,age, height, lots_of_properties):
    return Person(name, age, height, lots_of_properties)
# I would like to initialize multiple a_person objects with different params
def test_person_object_1(a_person.name = "alive", a_person.age = 33, a_person.height = 230, a_person.lots_of_properties.{}):
// test stuff
def test_person_object_2(a_person.name = "bob", a_person.age = 18, a_person.height = 180, a_person.lots_of_properties.{}):
// test stuff

但是我知道最后的语法是完全错误的。

要使用@pytest.mark.parametrize做到这一点,您所需要的就是定义期望在fixture中作为函数参数接收的参数,并确保在测试的@pytest.mark.parametrize中定义它们。如参数person_nameperson_age

import pytest

class Person:
    def __init__(self, name, age=None, height=None, lots_of_properties=None):
        self.name = name
        if age is not None:
            self.age = age
        if height is not None:
            self.height = height
        if lots_of_properties is not None:
            self.lots_of_properties["somepropertykey"] = "somepropertyvalue"

@pytest.fixture
def a_person(person_name: str, person_age: int) -> Person:
    return Person(person_name, person_age)

@pytest.mark.parametrize("person_name, person_age", [("simon", 32)])
def test_with_parameters(a_person):
    assert a_person.name == "simon"
    assert a_person.age == 32

但是这种简单的方法在大多数情况下是不实用的。随着代码库变得越来越复杂,需要更复杂和直接的测试。这种方法的缺点之一是必须为每个测试定义所有参数,即使测试只测试其中一个参数。为了克服这个问题,可以将参数定义为返回默认值的单独fixture。如person_nameperson_age装置

import pytest

class Person:
    def __init__(self, name, age=None, height=None, lots_of_properties=None):
        self.name = name
        if age is not None:
            self.age = age
        if height is not None:
            self.height = height
        if lots_of_properties is not None:
            self.lots_of_properties["somepropertykey"] = "somepropertyvalue"

@pytest.fixture
def person_name() -> str:
    return "simon"

@pytest.fixture
def person_age() -> int:
    return 32

@pytest.fixture
def a_person(person_name: str, person_age: int) -> Person:
    return Person(person_name, person_age)

def test_person_name(a_person):
    assert a_person.name == "simon"

def test_person_age(a_person):
    assert a_person.age == 32

@pytest.mark.parametrize("person_name", ["not simon"])
def test_with_parameter_person_name(a_person):
    assert a_person.name == "not simon"

@pytest.mark.parametrize("person_age", [20])
def test_with_parameter_person_age(a_person):
    assert a_person.age == 20

@pytest.mark.parametrize("person_name, person_age", [("person1", 20), ("person2", 22), ("person3", 24)])
def test_with_parameters(a_person):
    if a_person.name == "person1":
        assert a_person.age == 20
    elif a_person.name == "person2":
        assert a_person.age == 22
    elif a_person.name == "person3":
        assert a_person.age == 24
    else:
        assert False, "Incorrect person"

这样,test_with_parameter_person_name只能参数化与测试相关的参数,所有其他参数将从其他未参数化的fixture生成。

使用pytest标记@pytest.mark.parametrize的一种方法如下所示:

也可以看到文档的链接:https://docs.pytest.org/en/7.1.x/how-to/parametrize.html#pytest-mark-parametrize-parametrizing-test-functions

import pytest
class Person:
    def __init__(self, name, age=None, height=None, lots_of_properties=None):
        self.name = name
        if age is not None:
            self.age = age
        if height is not None:
            self.height = height
        if lots_of_properties is not None:
            self.lots_of_properties["somepropertykey"] = "somepropertyvalue"
@pytest.fixture
def a_person():
    return Person("simon", 32)
def test_person_name(a_person):
    assert a_person.name == "simon"
def test_person_age(a_person):
    assert a_person.age == 32
@pytest.mark.parametrize("field", [1,2,3])
def test_parametrize(a_person, field):
    if 'field' == 1:
        assert a_person.name == "simon"
    if 'field' == 2:
        assert a_person.age == 32
    if 'field' == 3:
        assert len(a_person.keys()) > 1
@pytest.mark.parametrize("field", [{1:Person("simon", 31)},{2:Person("simon", 32)},{3:Person("simon", 33)}])
def test_parametrize2(a_person, field):
    if [field.keys()][0] == 1:
        assert a_person.name == "simon"
    if [field.keys()][0] == 2:
        assert a_person.age == 32
    if [field.keys()][0] == 3:
        assert a_person.age == 33

最新更新