问题描述
我正在使用pytest
为正在开发的程序包运行测试用例。测试使用一个小图像文件,我将其保存为github资产。以下代码可以正常工作,但我认为pytest
每次运行新测试时都在下载映像,这会花费不必要的时间和资源。我试图弄清楚如何下载一次文件,然后在测试用例之间共享它
这是一些示例代码。
# -- in conftest.py --
import sys
import pytest
import os
import shutil
import requests
@pytest.fixture(scope="function")
def small_image(tmpdir):
url = 'https://github.com/.../sample_image_small.tif'
r = requests.get(url)
with open(os.path.join(str(tmpdir),'sample_image_small.tif'),'wb') as f:
f.write(r.content)
return os.path.join(str(tmpdir),'sample_image_small.tif')
然后是一些非常简单的测试用例,它们应该能够共享同一张图像。
# -- test_package.py --
import pytest
import os
@pytest.mark.usefixtures('small_image')
def test_ispath(small_image,compression):
assert os.path.exists(small_image)
def test_isfile(small_image,compression):
assert os.path.isfile(small_image)
现在,我相信pytest
会尝试单独隔离每个测试,这就是导致文件重复下载的原因。我尝试设置@pytest.fixture(scope="module")
而不是function
,但这产生了奇怪的错误:
ScopeMismatch: You tried to access the 'function' scoped fixture 'tmpdir' with a 'module' scoped request object,involved factories
解决方法
您可以使用相同的代码,只需自己处理临时文件,而不使用tmpdir
固定装置(不能在模块范围的固定装置中使用):
import os
import tempfile
import pytest
import requests
@pytest.fixture(scope="module")
def small_image():
url = 'https://github.com/.../sample_image_small.tif'
r = requests.get(url)
f = tempfile.NamedTemporaryFile(delete=False):
f.write(f.content)
yield f.name
os.remove(f.name)
这将创建文件,返回文件名,并在测试完成后删除文件。
编辑: @hoefling的回答显示了一种更标准的方法,我将把它留作参考。
,首先,请事先注意:tmpdir
/ tmpdir_factory
是旧的tmp_path
/ tmp_path_factory
灯具对的更好替代,它处理pathlib
对象已弃用的py.path
中的数据,请参见Temporary directories and files。
第二,如果要处理会话作用域(或模块作用域)的文件,tmp*_factory
固定装置就是为此而设计的。示例:
@pytest.fixture(scope='session')
def small_image(tmp_path_factory):
img = tmp_path_factory.getbasetemp() / 'sample_image_small.tif'
img.write_bytes(b'spam')
return img
sample_image_small.tif
现在将在每次测试运行中写入一次。
当然,正如@MrBean Bremen在他的回答中所建议的,使用tempfile
并没有错,这只是做同样的选择,只是使用标准的pytest
灯具。