@@ -437,3 +437,102 @@ def test_lastfailed_creates_cache_when_needed(self, testdir):
437
437
testdir .makepyfile (test_errored = 'def test_error():\n assert False' )
438
438
testdir .runpytest ('-q' , '--lf' )
439
439
assert os .path .exists ('.cache' )
440
+
441
+ def test_xfail_not_considered_failure (self , testdir ):
442
+ testdir .makepyfile ('''
443
+ import pytest
444
+ @pytest.mark.xfail
445
+ def test():
446
+ assert 0
447
+ ''' )
448
+ result = testdir .runpytest ()
449
+ result .stdout .fnmatch_lines ('*1 xfailed*' )
450
+ assert self .get_cached_last_failed (testdir ) == []
451
+
452
+ def test_xfail_strict_considered_failure (self , testdir ):
453
+ testdir .makepyfile ('''
454
+ import pytest
455
+ @pytest.mark.xfail(strict=True)
456
+ def test():
457
+ pass
458
+ ''' )
459
+ result = testdir .runpytest ()
460
+ result .stdout .fnmatch_lines ('*1 failed*' )
461
+ assert self .get_cached_last_failed (testdir ) == ['test_xfail_strict_considered_failure.py::test' ]
462
+
463
+ @pytest .mark .parametrize ('mark' , ['mark.xfail' , 'mark.skip' ])
464
+ def test_failed_changed_to_xfail_or_skip (self , testdir , mark ):
465
+ testdir .makepyfile ('''
466
+ import pytest
467
+ def test():
468
+ assert 0
469
+ ''' )
470
+ result = testdir .runpytest ()
471
+ assert self .get_cached_last_failed (testdir ) == ['test_failed_changed_to_xfail_or_skip.py::test' ]
472
+ assert result .ret == 1
473
+
474
+ testdir .makepyfile ('''
475
+ import pytest
476
+ @pytest.{mark}
477
+ def test():
478
+ assert 0
479
+ ''' .format (mark = mark ))
480
+ result = testdir .runpytest ()
481
+ assert result .ret == 0
482
+ assert self .get_cached_last_failed (testdir ) == []
483
+ assert result .ret == 0
484
+
485
+ def get_cached_last_failed (self , testdir ):
486
+ config = testdir .parseconfigure ()
487
+ return sorted (config .cache .get ("cache/lastfailed" , {}))
488
+
489
+ def test_cache_cumulative (self , testdir ):
490
+ """
491
+ Test workflow where user fixes errors gradually file by file using --lf.
492
+ """
493
+ # 1. initial run
494
+ test_bar = testdir .makepyfile (test_bar = """
495
+ def test_bar_1():
496
+ pass
497
+ def test_bar_2():
498
+ assert 0
499
+ """ )
500
+ test_foo = testdir .makepyfile (test_foo = """
501
+ def test_foo_3():
502
+ pass
503
+ def test_foo_4():
504
+ assert 0
505
+ """ )
506
+ testdir .runpytest ()
507
+ assert self .get_cached_last_failed (testdir ) == ['test_bar.py::test_bar_2' , 'test_foo.py::test_foo_4' ]
508
+
509
+ # 2. fix test_bar_2, run only test_bar.py
510
+ testdir .makepyfile (test_bar = """
511
+ def test_bar_1():
512
+ pass
513
+ def test_bar_2():
514
+ pass
515
+ """ )
516
+ result = testdir .runpytest (test_bar )
517
+ result .stdout .fnmatch_lines ('*2 passed*' )
518
+ # ensure cache does not forget that test_foo_4 failed once before
519
+ assert self .get_cached_last_failed (testdir ) == ['test_foo.py::test_foo_4' ]
520
+
521
+ result = testdir .runpytest ('--last-failed' )
522
+ result .stdout .fnmatch_lines ('*1 failed, 3 deselected*' )
523
+ assert self .get_cached_last_failed (testdir ) == ['test_foo.py::test_foo_4' ]
524
+
525
+ # 3. fix test_foo_4, run only test_foo.py
526
+ test_foo = testdir .makepyfile (test_foo = """
527
+ def test_foo_3():
528
+ pass
529
+ def test_foo_4():
530
+ pass
531
+ """ )
532
+ result = testdir .runpytest (test_foo , '--last-failed' )
533
+ result .stdout .fnmatch_lines ('*1 passed, 1 deselected*' )
534
+ assert self .get_cached_last_failed (testdir ) == []
535
+
536
+ result = testdir .runpytest ('--last-failed' )
537
+ result .stdout .fnmatch_lines ('*4 passed*' )
538
+ assert self .get_cached_last_failed (testdir ) == []
0 commit comments