如何在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,再结合参数化使用:
- 新增整合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)]
- 编写参数化测试:
@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
相关产品推荐
相关产品推荐

