25
25
26
26
import pytest
27
27
28
+ try :
29
+ from _pytest .junitxml import xml_key
30
+ except ImportError :
31
+ xml_key = "_xml" # type: ignore
32
+
28
33
LOAD_PROFILE_OPTION = "--hypothesis-profile"
29
34
VERBOSITY_OPTION = "--hypothesis-verbosity"
30
35
PRINT_STATISTICS_OPTION = "--hypothesis-show-statistics"
53
58
check to assure Hypothesis that you understand what you are doing.
54
59
"""
55
60
61
+ STATS_KEY = "_hypothesis_stats"
62
+
56
63
57
64
class StoringReporter :
58
65
def __init__ (self , config ):
@@ -255,9 +262,7 @@ def pytest_runtest_call(item):
255
262
256
263
def note_statistics (stats ):
257
264
stats ["nodeid" ] = item .nodeid
258
- item .hypothesis_statistics = base64 .b64encode (
259
- describe_statistics (stats ).encode ()
260
- ).decode ()
265
+ item .hypothesis_statistics = describe_statistics (stats )
261
266
262
267
with collector .with_value (note_statistics ):
263
268
with with_reporter (store ):
@@ -266,6 +271,16 @@ def note_statistics(stats):
266
271
if store .results :
267
272
item .hypothesis_report_information = list (store .results )
268
273
274
+ def _stash_get (config , key , default ):
275
+ if hasattr (config , "stash" ):
276
+ # pytest 7
277
+ return config .stash .get (key , default )
278
+ elif hasattr (config , "_store" ):
279
+ # pytest 5.4
280
+ return config ._store .get (key , default )
281
+ else :
282
+ return getattr (config , key , default )
283
+
269
284
@pytest .hookimpl (hookwrapper = True )
270
285
def pytest_runtest_makereport (item , call ):
271
286
report = (yield ).get_result ()
@@ -274,46 +289,42 @@ def pytest_runtest_makereport(item, call):
274
289
("Hypothesis" , "\n " .join (item .hypothesis_report_information ))
275
290
)
276
291
if hasattr (item , "hypothesis_statistics" ) and report .when == "teardown" :
292
+ stats = item .hypothesis_statistics
293
+ stats_base64 = base64 .b64encode (stats .encode ()).decode ()
294
+
277
295
name = "hypothesis-statistics-" + item .nodeid
278
- try :
279
- item .config ._xml .add_global_property (name , item .hypothesis_statistics )
280
- except AttributeError :
281
- # --junitxml not passed, or Pytest 4.5 (before add_global_property)
282
- # We'll fail xunit2 xml schema checks, upgrade pytest if you care.
283
- report .user_properties .append ((name , item .hypothesis_statistics ))
296
+
297
+ # Include hypothesis information to the junit XML report.
298
+ #
299
+ # Note that when `pytest-xdist` is enabled, `xml_key` is not present in the
300
+ # stash, so we don't add anything to the junit XML report in that scenario.
301
+ # https://github.com/pytest-dev/pytest/issues/7767#issuecomment-1082436256
302
+ xml = _stash_get (item .config , xml_key , None )
303
+ if xml :
304
+ xml .add_global_property (name , stats_base64 )
305
+
306
+ # If there's a terminal report, include our summary stats for each test
307
+ terminalreporter = item .config .pluginmanager .getplugin ("terminalreporter" )
308
+ if terminalreporter is not None :
309
+ # ideally, we would store this on terminalreporter.config.stash, but
310
+ # pytest-xdist doesn't copy that back to the controller
311
+ report .__dict__ [STATS_KEY ] = stats
312
+
284
313
# If there's an HTML report, include our summary stats for each test
285
- stats = base64 .b64decode (item .hypothesis_statistics .encode ()).decode ()
286
314
pytest_html = item .config .pluginmanager .getplugin ("html" )
287
315
if pytest_html is not None : # pragma: no cover
288
316
report .extra = getattr (report , "extra" , []) + [
289
317
pytest_html .extras .text (stats , name = "Hypothesis stats" )
290
318
]
291
319
292
320
def pytest_terminal_summary (terminalreporter ):
293
- if not terminalreporter .config .getoption (PRINT_STATISTICS_OPTION ):
294
- return
295
- terminalreporter .section ("Hypothesis Statistics" )
296
-
297
- def report (properties ):
298
- for name , value in properties :
299
- if name .startswith ("hypothesis-statistics-" ):
300
- if hasattr (value , "uniobj" ):
301
- # Under old versions of pytest, `value` was a `py.xml.raw`
302
- # rather than a string, so we get the (unicode) string off it.
303
- value = value .uniobj
304
- line = base64 .b64decode (value .encode ()).decode () + "\n \n "
305
- terminalreporter .write_line (line )
306
-
307
- try :
308
- global_properties = terminalreporter .config ._xml .global_properties
309
- except AttributeError :
310
- # terminalreporter.stats is a dict, where the empty string appears to
311
- # always be the key for a list of _pytest.reports.TestReport objects
312
- for test_report in terminalreporter .stats .get ("" , []):
313
- if test_report .when == "teardown" :
314
- report (test_report .user_properties )
315
- else :
316
- report (global_properties )
321
+ if terminalreporter .config .getoption (PRINT_STATISTICS_OPTION ):
322
+ terminalreporter .section ("Hypothesis Statistics" )
323
+ for reports in terminalreporter .stats .values ():
324
+ for report in reports :
325
+ stats = report .__dict__ .get (STATS_KEY )
326
+ if stats :
327
+ terminalreporter .write_line (stats + "\n \n " )
317
328
318
329
def pytest_collection_modifyitems (items ):
319
330
if "hypothesis" not in sys .modules :
0 commit comments