File tree 3 files changed +52
-5
lines changed
3 files changed +52
-5
lines changed Original file line number Diff line number Diff line change 23
23
from .._code import getfslineno
24
24
from ..compat import NOTSET
25
25
from ..compat import NotSetType
26
+ from _pytest ._raises_group import AbstractMatcher
26
27
from _pytest .config import Config
27
28
from _pytest .deprecated import check_ispytest
28
29
from _pytest .deprecated import MARKED_FIXTURE
@@ -459,7 +460,10 @@ def __call__(
459
460
* conditions : str | bool ,
460
461
reason : str = ...,
461
462
run : bool = ...,
462
- raises : None | type [BaseException ] | tuple [type [BaseException ], ...] = ...,
463
+ raises : None
464
+ | type [BaseException ]
465
+ | tuple [type [BaseException ], ...]
466
+ | AbstractMatcher [BaseException ] = ...,
463
467
strict : bool = ...,
464
468
) -> MarkDecorator : ...
465
469
Original file line number Diff line number Diff line change 12
12
import traceback
13
13
from typing import Optional
14
14
15
+ from _pytest ._raises_group import AbstractMatcher
15
16
from _pytest .config import Config
16
17
from _pytest .config import hookimpl
17
18
from _pytest .config .argparsing import Parser
@@ -201,7 +202,12 @@ class Xfail:
201
202
reason : str
202
203
run : bool
203
204
strict : bool
204
- raises : tuple [type [BaseException ], ...] | None
205
+ raises : (
206
+ type [BaseException ]
207
+ | tuple [type [BaseException ], ...]
208
+ | AbstractMatcher [BaseException ]
209
+ | None
210
+ )
205
211
206
212
207
213
def evaluate_xfail_marks (item : Item ) -> Xfail | None :
@@ -277,11 +283,20 @@ def pytest_runtest_makereport(
277
283
elif not rep .skipped and xfailed :
278
284
if call .excinfo :
279
285
raises = xfailed .raises
280
- if raises is not None and not isinstance (call .excinfo .value , raises ):
281
- rep .outcome = "failed"
282
- else :
286
+ if raises is None or (
287
+ (
288
+ isinstance (raises , (type , tuple ))
289
+ and isinstance (call .excinfo .value , raises )
290
+ )
291
+ or (
292
+ isinstance (raises , AbstractMatcher )
293
+ and raises .matches (call .excinfo .value )
294
+ )
295
+ ):
283
296
rep .outcome = "skipped"
284
297
rep .wasxfail = xfailed .reason
298
+ else :
299
+ rep .outcome = "failed"
285
300
elif call .when == "call" :
286
301
if xfailed .strict :
287
302
rep .outcome = "failed"
Original file line number Diff line number Diff line change 11
11
from _pytest ._raises_group import RaisesGroup
12
12
from _pytest ._raises_group import repr_callable
13
13
from _pytest .outcomes import Failed
14
+ from _pytest .pytester import Pytester
14
15
import pytest
15
16
16
17
@@ -1135,3 +1136,30 @@ def test_assert_matches() -> None:
1135
1136
1136
1137
# but even if we add assert_matches, will people remember to use it?
1137
1138
# other than writing a linter rule, I don't think we can catch `assert Matcher(...).matches`
1139
+
1140
+
1141
+ # https://github.com/pytest-dev/pytest/issues/12504
1142
+ def test_xfail_raisesgroup (pytester : Pytester ) -> None :
1143
+ pytester .makepyfile (
1144
+ """
1145
+ import pytest
1146
+ @pytest.mark.xfail(raises=pytest.RaisesGroup(ValueError))
1147
+ def test_foo() -> None:
1148
+ raise ExceptionGroup("foo", [ValueError()])
1149
+ """
1150
+ )
1151
+ result = pytester .runpytest ()
1152
+ result .assert_outcomes (xfailed = 1 )
1153
+
1154
+
1155
+ def test_xfail_Matcher (pytester : Pytester ) -> None :
1156
+ pytester .makepyfile (
1157
+ """
1158
+ import pytest
1159
+ @pytest.mark.xfail(raises=pytest.Matcher(ValueError))
1160
+ def test_foo() -> None:
1161
+ raise ValueError
1162
+ """
1163
+ )
1164
+ result = pytester .runpytest ()
1165
+ result .assert_outcomes (xfailed = 1 )
You can’t perform that action at this time.
0 commit comments