@@ -273,6 +273,9 @@ def __init__(self, logfile, prefix):
273
273
self .node_reporters = {} # nodeid -> _NodeReporter
274
274
self .node_reporters_ordered = []
275
275
self .global_properties = []
276
+ # List of reports that failed on call but teardown is pending.
277
+ self .open_reports = []
278
+ self .cnt_double_fail_tests = 0
276
279
277
280
def finalize (self , report ):
278
281
nodeid = getattr (report , 'nodeid' , report )
@@ -332,14 +335,33 @@ def pytest_runtest_logreport(self, report):
332
335
-> teardown node2
333
336
-> teardown node1
334
337
"""
338
+ close_report = None
335
339
if report .passed :
336
340
if report .when == "call" : # ignore setup/teardown
337
341
reporter = self ._opentestcase (report )
338
342
reporter .append_pass (report )
339
343
elif report .failed :
344
+ if report .when == "teardown" :
345
+ # The following vars are needed when xdist plugin is used
346
+ report_wid = getattr (report , "worker_id" , None )
347
+ report_ii = getattr (report , "item_index" , None )
348
+ close_report = next (
349
+ (rep for rep in self .open_reports
350
+ if (rep .nodeid == report .nodeid and
351
+ getattr (rep , "item_index" , None ) == report_ii and
352
+ getattr (rep , "worker_id" , None ) == report_wid
353
+ )
354
+ ), None )
355
+ if close_report :
356
+ # We need to open new testcase in case we have failure in
357
+ # call and error in teardown in order to follow junit
358
+ # schema
359
+ self .finalize (close_report )
360
+ self .cnt_double_fail_tests += 1
340
361
reporter = self ._opentestcase (report )
341
362
if report .when == "call" :
342
363
reporter .append_failure (report )
364
+ self .open_reports .append (report )
343
365
else :
344
366
reporter .append_error (report )
345
367
elif report .skipped :
@@ -348,6 +370,17 @@ def pytest_runtest_logreport(self, report):
348
370
self .update_testcase_duration (report )
349
371
if report .when == "teardown" :
350
372
self .finalize (report )
373
+ report_wid = getattr (report , "worker_id" , None )
374
+ report_ii = getattr (report , "item_index" , None )
375
+ close_report = next (
376
+ (rep for rep in self .open_reports
377
+ if (rep .nodeid == report .nodeid and
378
+ getattr (rep , "item_index" , None ) == report_ii and
379
+ getattr (rep , "worker_id" , None ) == report_wid
380
+ )
381
+ ), None )
382
+ if close_report :
383
+ self .open_reports .remove (close_report )
351
384
352
385
def update_testcase_duration (self , report ):
353
386
"""accumulates total duration for nodeid from given report and updates
@@ -380,8 +413,9 @@ def pytest_sessionfinish(self):
380
413
suite_stop_time = time .time ()
381
414
suite_time_delta = suite_stop_time - self .suite_start_time
382
415
383
- numtests = self .stats ['passed' ] + self .stats ['failure' ] + self .stats ['skipped' ] + self .stats ['error' ]
384
-
416
+ numtests = (self .stats ['passed' ] + self .stats ['failure' ] +
417
+ self .stats ['skipped' ] + self .stats ['error' ] -
418
+ self .cnt_double_fail_tests )
385
419
logfile .write ('<?xml version="1.0" encoding="utf-8"?>' )
386
420
387
421
logfile .write (Junit .testsuite (
0 commit comments