例如,我有以下测试数据:
"license": "UNLICENSED",
我需要从此PARAMS = {'pic1': [1, 2, 3], 'pic2': [14, 15], 'pic3': [100, 200, 300]}
下载每个关键图片并生成单独的测试PARAMS
,该测试将使用此图片。之后,[1, 2, 3]
对的每个测试结束时,请删除图片,然后下载下一个,依此类推...
粗略地说,生成的测试应如下所示:
'pic1': [1, 2, 3]
但其中将包含下载图像逻辑。
我在pytest中找不到方法。
请帮助。
答案 0 :(得分:4)
对我来说,这似乎是一项间接参数化任务。
第一件事:pytest.mark.parametrize
期望参数作为元组列表传递,数据按arg名称排序,例如:
@pytest.mark.parametrize('spam,eggs', [(1, 2), (3, 4), (5, 6)])
将生成三个测试:
spam=1, eggs=2
,spam=3, eggs=4
,spam=5, eggs=6
。因此,您必须将PARAMS
字典转换为元组列表,每个字典键具有一个数字。有很多方法可以做到这一点,一种解决方案是:
PARAMS = {'pic1': [1, 2, 3],
'pic2': [14, 15],
'pic3': [100, 200, 300]}
test_pic_params = [(key, el) for key, nums in PARAMS.items()
for el in nums]
@pytest.mark.parametrize('file,num', test_pic_params)
def test_pic(file, num):
assert True
检查测试是否正确生成:
$ pytest --collect-only --quiet test_spam.py
test_spam.py::test_pic[pic1-1]
test_spam.py::test_pic[pic1-2]
test_spam.py::test_pic[pic1-3]
test_spam.py::test_pic[pic2-14]
test_spam.py::test_pic[pic2-15]
test_spam.py::test_pic[pic3-100]
test_spam.py::test_pic[pic3-200]
test_spam.py::test_pic[pic3-300]
no tests ran in 0.07 seconds
现在,您要在测试之前处理file
参数,因此测试将获取pic1
而不是pic1
的下载文件。这可以通过间接参数化来完成。您需要做的是:
file
的灯具(重要的是,灯具必须与测试参数具有相同的名称,否则pytest
将无法识别并应用它)indirect=['file']
添加到参数化标记中。这样,pic1
首先传递到file()
固定装置,然后将固定装置的结果传递到测试。扩展示例:
import pathlib
import pytest
PARAMS = {'pic1': [1, 2, 3],
'pic2': [14, 15],
'pic3': [100, 200, 300]}
test_pic_params = [(key, el) for key, nums in PARAMS.items()
for el in nums]
@pytest.fixture
def file(request):
pic = request.param
# this will just create an empty file named 'pic1' etc;
# replace it with file download logic
filename = pathlib.Path(pic)
filename.touch()
# pass filename instead of pic to test
yield filename
# after test finishes, we remove downloaded file
filename.unlink()
@pytest.mark.parametrize('file,num', test_pic_params, indirect=['file'])
def test_pic(file, num):
assert file.is_file()
我需要做的是在测试
'pic1'
之后删除文件test_pic[pic1-1] , test_pic[pic1-2], test_pic[pic1-3]
。然后下载新文件pic2
。
尽管肯定有可能,但是请记住,这将违反单个测试运行的原子性,因此,例如,您将失去并行运行测试的能力。
如果您想跟踪测试运行的当前状态,只需在灯具中进行即可。当数字是相应列表中的第一个数字时,下载文件;删除最后一个号码上的文件:
@pytest.fixture
def file(request):
pic = request.param
num = request.node.callspec.params['num']
filename = pathlib.Path(pic)
if num == PARAMS[pic][0]: # download here
filename.touch()
yield filename
if num == PARAMS[pic][-1]: # remove here
filename.unlink()
一种更好的IMO方法是使用disk cache,在首次下载时缓存文件;这会使测试再次运行原子化。