You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在pytest中利用两个不同Fixture的不同数据参数化测试

pytest Fixture结合参数化测试的重构实现

问题描述

我有以下多个pytest Fixture:

@pytest.fixture
def articles_new(category):
    article_new_1 = ArticleFactory.create(category=category["category_1"], status=ArticleStatusChoices.NEW)
    article_new_2 = ArticleFactory.create(category=category["category_2"], status=ArticleStatusChoices.NEW)
    return {"article_new_1": article_new_1, "article_new_2": article_new_2}

@pytest.fixture
def articles_published_with_readers(category):
    article_published_with_readers_1 = ArticleFactory.create(
        category=category["category_2"],
        readers=ArticleRoleTypesChoices.EMPLOYEE,
        status=ArticleStatusChoices.PUBLISHED,
    )
    return {"article_published_with_readers_1": article_published_with_readers_1}

@pytest.fixture
def category(product):
    category_1 = CategoryFactory.create(product=product["product_1"])
    category_2 = CategoryFactory.create(product=product["product_2"])
    return {"category_1": category_1, "category_2": category_2}

@pytest.fixture
def product():
    product_1 = ProductFactory.create()
    product_2 = ProductFactory.create()
    return {"product_1": product_1, "product_2": product_2}

原本的测试用例如下:

def test_articles(self, client, user):
    client.force_login(user)
    
    res = client.get(reverse("get_article", kwargs={"article_guid": article_new_1.guid}))
    assert res.status_code == 200

    res = client.get(reverse("get_article", kwargs={"article_guid": article_published_with_readers_1.guid}))
    assert res.status_code == 403

我想把它重构为参数化形式,但不知道如何实现:

@pytest.mark.parametrize(
        "article, expected",
        [
            ......
        ],
    )
def test_articles(self, client, user, article, expected):
    client.force_login(user)
    
    res = client.get(reverse("get_article", kwargs={"article_guid": article.guid}))
    assert res.status_code == expected

注意:article_new_1和article_published_with_readers_1属于不同分类。


解决方案

方法一:动态获取Fixture实例(无需修改原有Fixture)

通过request对象动态获取不同Fixture中的文章实例,直接适配参数化需求:

@pytest.mark.parametrize(
    "fixture_name, article_key, expected",
    [
        # 参数对应:Fixture名称、实例键名、预期状态码
        ("articles_new", "article_new_1", 200),
        ("articles_published_with_readers", "article_published_with_readers_1", 403),
    ],
)
def test_articles(self, client, user, request, fixture_name, article_key, expected):
    client.force_login(user)
    # 从指定Fixture中获取数据
    fixture_data = request.getfixturevalue(fixture_name)
    # 取出目标文章实例
    article = fixture_data[article_key]
    
    res = client.get(reverse("get_article", kwargs={"article_guid": article.guid}))
    assert res.status_code == expected

方法二:整合测试实例到统一Fixture

如果希望参数化直接接收文章实例,可以创建一个整合所有测试所需实例的Fixture,再结合参数化使用:

  1. 新增整合Fixture:
@pytest.fixture
def test_article_instances(category):
    # 复用原有逻辑创建需要的文章实例
    article_new_1 = ArticleFactory.create(category=category["category_1"], status=ArticleStatusChoices.NEW)
    article_published_with_readers_1 = ArticleFactory.create(
        category=category["category_2"],
        readers=ArticleRoleTypesChoices.EMPLOYEE,
        status=ArticleStatusChoices.PUBLISHED,
    )
    # 返回参数化需要的(实例, 预期状态码)元组列表
    return [(article_new_1, 200), (article_published_with_readers_1, 403)]
  1. 编写参数化测试:
@pytest.mark.parametrize("article, expected", indirect=True)
def test_articles(self, client, user, article, expected):
    client.force_login(user)
    
    res = client.get(reverse("get_article", kwargs={"article_guid": article.guid}))
    assert res.status_code == expected

方案说明

  • 方法一无需改动原有Fixture结构,适合已有Fixture稳定、不想额外维护的场景,通过动态获取的方式灵活适配不同Fixture中的实例。
  • 方法二把测试所需实例统一管理,参数化代码更简洁,但需要维护整合后的Fixture,适合后续会新增更多测试实例的场景。

内容的提问来源于stack exchange,提问作者serg

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.28 12:50:22