@@ -95,6 +95,59 @@ any guaranteed order, but you can control this with these options:
9595 in version ``1.21 ``.
9696
9797
98+ Making session-scoped fixtures execute only once
99+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
100+
101+ ``pytest-xdist `` is designed so that each worker process will perform its own collection and execute
102+ a subset of all tests. This means that tests in different processes requesting a high-level
103+ scoped fixture (for example ``session ``) will execute the fixture code more than once, which
104+ breaks expectations and might be undesired in certain situations.
105+
106+ While ``pytest-xdist `` does not have a builtin support for ensuring a session-scoped fixture is
107+ executed exactly once, this can be achieved by using a lock file for inter-process communication.
108+
109+ The example below needs to execute the fixture ``session_data `` only once (because it is
110+ resource intensive, or needs to execute only once to define configuration options, etc), so it makes
111+ use of a `FileLock <https://pypi.org/project/filelock/ >`_ to produce the fixture data only once
112+ when the first process requests the fixture, while the other processes will then read
113+ the data from a file.
114+
115+ Here is the code:
116+
117+ .. code-block :: python
118+
119+ import json
120+
121+ import pytest
122+ from filelock import FileLock
123+
124+
125+ @pytest.fixture (scope = " session" )
126+ def session_data (tmp_path_factory , worker_id ):
127+ if not worker_id:
128+ # not executing in with multiple workers, just produce the data and let
129+ # pytest's fixture caching do its job
130+ return produce_expensive_data()
131+
132+ # get the temp directory shared for by all workers
133+ root_tmp_dir = tmp_path_factory.getbasetemp().parent
134+
135+ fn = root_tmp_dir / " data.json"
136+ with FileLock(str (fn) + " .lock" ):
137+ if fn.is_file():
138+ data = json.loads(fn.read_text())
139+ else :
140+ data = produce_expensive_data()
141+ fn.write_text(json.dumps(data))
142+ return data
143+
144+
145+ The example above can also be use in cases a fixture needs to execute exactly once per test session, like
146+ initializing a database service and populating initial tables.
147+
148+ This technique might not work for every case, but should be a starting point for many situations
149+ where executing a high-scope fixture exactly once is important.
150+
98151Running tests in a Python subprocess
99152------------------------------------
100153
0 commit comments