我有多个测试需要昂贵的生成文件。 我希望在每次测试运行时重新生成该文件,但最多一次。 让事情变得复杂的是,这些测试以及文件都依赖于输入参数。
def expensive(param) -> Path:
# Generate file and return its path.
@mark.parametrize('input', TEST_DATA)
class TestClass:
def test_one(self, input) -> None:
check_expensive1(expensive(input))
def test_two(self, input) -> None:
check_expensive2(expensive(input))
如何确保即使并行运行这些测试,该文件也不会跨线程重新生成? 对于上下文,我将 Makefile 的测试基础设施移植到 pytest。
我可以使用基于文件的锁进行同步,但我确信其他人也遇到过这个问题,并且宁愿使用现有的解决方案。
使用
functools.cache
对于单线程非常有效。带有 scope="module"
的夹具根本不起作用,因为参数 input
位于函数范围内。
pytest-xdist 文档部分中有一个现有的解决方案“使会话范围的装置仅执行一次”:
import json
import pytest
from filelock import FileLock
@pytest.fixture(scope="session")
def session_data(tmp_path_factory, worker_id):
if worker_id == "master":
# not executing in with multiple workers, just produce the data and let
# pytest's fixture caching do its job
return produce_expensive_data()
# get the temp directory shared by all workers
root_tmp_dir = tmp_path_factory.getbasetemp().parent
fn = root_tmp_dir / "data.json"
with FileLock(str(fn) + ".lock"):
if fn.is_file():
data = json.loads(fn.read_text())
else:
data = produce_expensive_data()
fn.write_text(json.dumps(data))
return data