如何避免重复编写三次Pytest测试函数?能否用fixture参数化?
复用结构相似的Pytest测试函数
你可以通过参数化避免重复编写测试函数,pytest提供了两种常用实现方式:直接使用@pytest.mark.parametrize装饰器,或者结合参数化fixture。以下是具体方案:
问题回顾
你当前的测试代码重复度很高,三个函数仅在data.BuildZone的调用参数和目标文件路径上有差异:
from kingarthur import data from pathlib import Path def test_BuildZoneA(): zone_path = Path('home/stevethewizard/zoneA.txt') data.BuildZone('t', 's', zone_path, source_list=['spell1', 'spell2']) assert zone_path.is_file() == True assert zone_path.stat().st_size > 0 def test_BuildZoneB(): zone_path = Path('home/stevethewizard/zoneB.txt') data.BuildZone('t', 's', zone_path, cust_source_path='home/stevethewizard/spells/spells_master.txt') assert zone_path.is_file() == True assert zone_path.stat().st_size > 0 def test_BuildZoneC(): zone_path = Path('home/stevethewizard/zoneC.txt') data.BuildZone('t', 's', zone_path) assert zone_path.is_file() == True assert zone_path.stat().st_size > 0
方案1:使用@pytest.mark.parametrize直接参数化
这是最简洁的实现方式,把每个测试用例的差异参数整理成参数组,通过装饰器传递给单个测试函数:
import pytest from kingarthur import data from pathlib import Path # 定义参数组:每个元素是(zone文件名, BuildZone的关键字参数字典) test_cases = [ ("zoneA.txt", {"source_list": ['spell1', 'spell2']}), ("zoneB.txt", {"cust_source_path": 'home/stevethewizard/spells/spells_master.txt'}), ("zoneC.txt", {}) # 无额外参数 ] @pytest.mark.parametrize("zone_filename, build_kwargs", test_cases) def test_BuildZone(zone_filename, build_kwargs): zone_path = Path(f'home/stevethewizard/{zone_filename}') # 传递固定参数+可变关键字参数 data.BuildZone('t', 's', zone_path, **build_kwargs) assert zone_path.is_file() assert zone_path.stat().st_size > 0
运行时pytest会自动生成3个独立测试用例,分别对应原有的三个测试函数,测试名称会附带参数标识,方便问题定位。
方案2:使用参数化fixture
如果参数需要在多个测试函数中复用,或需要更复杂的初始化逻辑,可以用参数化fixture封装参数逻辑:
import pytest from kingarthur import data from pathlib import Path @pytest.fixture(params=[ ("zoneA.txt", {"source_list": ['spell1', 'spell2']}), ("zoneB.txt", {"cust_source_path": 'home/stevethewizard/spells/spells_master.txt'}), ("zoneC.txt", {}) ]) def zone_test_data(request): # 返回每个测试用例的路径和BuildZone参数 zone_filename, build_kwargs = request.param zone_path = Path(f'home/stevethewizard/{zone_filename}') return zone_path, build_kwargs def test_BuildZone(zone_test_data): zone_path, build_kwargs = zone_test_data data.BuildZone('t', 's', zone_path, **build_kwargs) assert zone_path.is_file() assert zone_path.stat().st_size > 0
这种方式的优势是参数逻辑可封装共享,其他测试函数也能直接依赖该fixture,适合多测试场景的参数复用。
两种方案都能实现测试代码复用,@pytest.mark.parametrize更适合单个测试函数的参数化,参数化fixture则更适配多测试场景的参数共享。
内容的提问来源于stack exchange,提问作者WarnkeIsKey
相关产品推荐
相关产品推荐

