我正在尝试使用pytest-xdist来使我的测试并行运行, 问题是每个线程都将转到与所有测试共享的夹具,并根据线程号执行该线程。
这引起了我一个问题,因为该夹具的作用是为测试创建数据,一旦创建了数据,我就错了,因为它已经被创建(通过REST)。
conftest.py:
lock = threading.Lock()
@pytest.fixture(scope=session)
def init_data(request):
lock.acquire()
try:
data = []
if checking_data_not_created():
data.append(some_rest_command_creating_data_1())
data.append(some_rest_command_creating_data_2())
finally:
lock.release()
yield data
lock.acquire()
try:
remove_all_data()
finally:
lock.release()
tests_class.py:
class classTests():
def first_test(init_data):
test body and validation....
def second_test(init_data):
test body and validation....
我正在使用以下命令: pytest -v -n2
假定第一个线程应运行first_test() 和第二个线程应该运行second_test() 其中一个将始终失败,因为第一个已经在Fixtures部分中创建了数据,另一个线程将异常,并且他应运行的所有测试都将失败。
如您所见,我试图使用锁来同步线程,但是它也无法正常工作。
知道如何解决此问题吗?
谢谢。
答案 0 :(得分:0)
该方法不适用于pytest-xdist,因为它使用多处理而非多线程,但是可以与pytest-parallel一起使用--tests-per-worker选项,它将使用多个线程运行测试。
在使用以下夹具的多线程pytest执行中,数据将仅设置一次并清理一次:
conftest.py:
lock = threading.Lock()
threaded_count = 0
@pytest.fixture(scope='session')
def init_data():
global lock
global threaded_count
lock.acquire()
threaded_count += 1
try:
if threaded_count == 1:
# Setup Data Once
data = setup_data()
finally:
lock.release()
yield data
lock.acquire()
threaded_count -= 1
try:
if threaded_count == 0:
# Cleanup Data Once
data = cleaup_data()
finally:
lock.release()
命令:
pytest -v-每个工人测试2
答案 1 :(得分:0)
请注意,pytest-xdist不支持'session'
范围内的灯具。 pytest-xdist中的'session'
范围内的固定装置实际上是指特定于进程的会话级固定装置,因此将为每个进程分别创建和拆除固定装置,并在进程之间不共享固定装置的状态。有一些长期存在的建议将真正的会话范围的固定装置添加到pytest-xdist中,并对其进行锁定和共享,但是它们都遇到了许多经典原因,不惜一切代价避免使用锁和线程进行多线程或多处理。同步,因此pytest-xdist开发人员严重不重视它(这是可以理解的)。
答案 2 :(得分:0)
Python xdist has a way to do this。
我相信你的例子,应用他们的建议看起来像这样:
def create_data():
data = []
data.append(some_rest_command_creating_data_1())
data.append(some_rest_command_creating_data_2())
return data
@pytest.fixture(scope="session")
def session_data(request, tmp_path_factory, worker_id):
if worker_id == "master":
# Not running multiple processes, just create the data.
data = create_data()
else:
# Running multiple processes, manage lockfile.
root_tmp_dir = tmp_path_factory.getbasetemp().parent
fn = root_tmp_dir / "data.json"
with FileLock(str(fn) + ".lock"):
if fn.is_file():
# Data has been created, read it in.
data = json.loads(fn.read_text())
else:
# Data not created, create and write it out.
data = create_data()
fn.write_text(json.dumps(data))
yield data
remove_all_data()
与您的示例不同,本示例通过保存在 data
共享临时测试目录中的锁文件提供 tmp_path_factory.getbasetemp().parent
,即 provided with pytest。