Skip to content

Commit 76c1bf8

Browse files
authored
error report refactoring (fixes #205 fixes #201 fixes #169 via #208)
1 parent 07438c1 commit 76c1bf8

23 files changed

+717
-208
lines changed

.gitignore

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
.DS_Store
22
.idea
33
.tox
4-
.cache
4+
.pytest_cache
55
.python-version
66

77
*.pyc

allure-behave/features/steps/report_steps.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
from allure_commons_test.result import has_attachment
88
from allure_commons_test.result import has_parameter
99
from allure_commons_test.result import has_status_details
10-
from allure_commons_test.result import with_status_message
10+
from allure_commons_test.result import with_message_contains
1111
from allure_commons_test.container import has_container
1212
from allure_commons_test.container import has_before, has_after
1313
from allure_commons_test.label import has_severity
@@ -86,7 +86,7 @@ def step_status(context, item, status):
8686
@then(u'this {item} has status details with message "{message}"')
8787
def step_status(context, item, message):
8888
context_matcher = getattr(context, item)
89-
matcher = partial(context_matcher, has_status_details, with_status_message, message)
89+
matcher = partial(context_matcher, has_status_details, with_message_contains, message)
9090
assert_that(context.allure_report, matcher())
9191

9292

allure-pytest/src/listener.py

Lines changed: 21 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
from allure_pytest.utils import allure_full_name, allure_package, allure_name
2020
from allure_pytest.utils import get_status, get_status_details
2121
from allure_pytest.utils import get_outcome_status, get_outcome_status_details
22+
from allure_pytest.utils import get_pytest_report_status
2223

2324

2425
class AllureListener(object):
@@ -142,45 +143,38 @@ def pytest_fixture_post_finalizer(self, fixturedef):
142143
@pytest.hookimpl(hookwrapper=True)
143144
def pytest_runtest_makereport(self, item, call):
144145
uuid = self._cache.set(item.nodeid)
146+
145147
report = (yield).get_result()
146-
allure_item = self.allure_logger.get_item(uuid)
147-
status = allure_item.status or None
148+
149+
test_result = self.allure_logger.get_test(uuid)
150+
status = get_pytest_report_status(report)
148151
status_details = None
149152

150-
if call.excinfo and hasattr(call.excinfo.value, 'msg'):
151-
status_details = StatusDetails(message=call.excinfo.value.msg)
152-
elif hasattr(report, 'wasxfail'):
153-
status_details = StatusDetails(message=report.wasxfail)
154-
elif report.failed:
153+
if call.excinfo:
155154
status_details = StatusDetails(message=call.excinfo.exconly(), trace=report.longreprtext)
155+
if (status != Status.SKIPPED
156+
and not (call.excinfo.errisinstance(AssertionError)
157+
or call.excinfo.errisinstance(pytest.fail.Exception))):
158+
status = Status.BROKEN
159+
160+
if status == Status.PASSED and hasattr(report, 'wasxfail'):
161+
reason = report.wasxfail
162+
message = 'XPASS {reason}'.format(reason=reason) if reason else 'XPASS'
163+
status_details = StatusDetails(message=message)
156164

157165
if report.when == 'setup':
158-
if report.passed:
159-
status = Status.PASSED
160-
if report.failed:
161-
status = Status.BROKEN
162-
if report.skipped:
163-
status = Status.SKIPPED
166+
test_result.status = status
167+
test_result.statusDetails = status_details
164168

165169
if report.when == 'call':
166-
if report.passed and status == Status.PASSED:
167-
pass
168-
if report.failed:
169-
status = Status.FAILED
170-
if report.skipped:
171-
status = Status.SKIPPED
170+
if test_result.status == Status.PASSED:
171+
test_result.status = status
172+
test_result.statusDetails = status_details
172173

173174
if report.when == 'teardown':
174-
if report.failed and status == Status.PASSED:
175-
status = Status.BROKEN
176-
177-
test_result = self.allure_logger.get_test(uuid)
178-
if test_result:
179-
if status_details:
175+
if status in (Status.FAILED, Status.BROKEN) and test_result.status == Status.PASSED:
180176
test_result.status = status
181177
test_result.statusDetails = status_details
182-
else:
183-
test_result.status = status
184178

185179
@allure_commons.hookimpl
186180
def attach_data(self, body, name, attachment_type, extension):

allure-pytest/src/utils.py

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -120,16 +120,24 @@ def get_outcome_status_details(outcome):
120120

121121
def get_status(exception):
122122
if exception:
123-
if isinstance(exception, AssertionError):
123+
if isinstance(exception, AssertionError) or isinstance(exception, pytest.fail.Exception):
124124
return Status.FAILED
125125
elif isinstance(exception, pytest.skip.Exception):
126126
return Status.SKIPPED
127-
return Status.PASSED
127+
return Status.BROKEN
128+
else:
129+
return Status.PASSED
128130

129131

130132
def get_status_details(exception_type, exception, exception_traceback):
131-
if isinstance(exception, pytest.skip.Exception):
132-
return StatusDetails(message=exception.msg)
133-
elif exception:
134-
return StatusDetails(message=format_exception(exception_type, exception),
135-
trace=format_traceback(exception_traceback))
133+
message = format_exception(exception_type, exception)
134+
trace = format_traceback(exception_traceback)
135+
return StatusDetails(message=message, trace=trace) if message or trace else None
136+
137+
138+
def get_pytest_report_status(pytest_report):
139+
pytest_statuses = ('failed', 'passed', 'skipped')
140+
statuses = (Status.FAILED, Status.PASSED, Status.SKIPPED)
141+
for pytest_status, status in zip(pytest_statuses, statuses):
142+
if getattr(pytest_report, pytest_status):
143+
return status

allure-pytest/test/fixtures/function_scope/finalizers_simple_test.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ def test_two_fixures_with_finalizer(fixture_with_passed_finalizer, fixture_faile
5555
... finalizer='failed_finalizer'),
5656
... with_status('failed'),
5757
... has_status_details(
58-
... with_status_message('AssertionError')
58+
... with_message_contains('AssertionError')
5959
... )
6060
... )
6161
... )

allure-pytest/test/fixtures/function_scope/fixtures_parametrization_test.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ def test_function_scope_parametrized_fixture(parametrized_fixture):
2626
... has_before('parametrized_fixture',
2727
... with_status('passed' if passed else 'failed'),
2828
... has_status_details(
29-
... with_status_message('AssertionError')
29+
... with_message_contains('AssertionError')
3030
... ) if not passed else anything()
3131
... )
3232
... )
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
import pytest
2+
3+
4+
def test_passed():
5+
"""
6+
>>> allure_report = getfixture('allure_report')
7+
>>> assert_that(allure_report,
8+
... has_test_case('test_passed',
9+
... with_status('passed')
10+
... )
11+
... )
12+
"""
13+
pass
14+
15+
16+
def test_failed():
17+
"""
18+
>>> allure_report = getfixture('allure_report')
19+
>>> assert_that(allure_report,
20+
... has_test_case('test_failed',
21+
... with_status('failed'),
22+
... has_status_details(with_message_contains("AssertionError"),
23+
... with_trace_contains("def test_failed():")
24+
... )
25+
... )
26+
... )
27+
"""
28+
assert False
29+
30+
31+
def test_broken():
32+
"""
33+
>>> allure_report = getfixture('allure_report')
34+
>>> assert_that(allure_report,
35+
... has_test_case('test_broken',
36+
... with_status('broken'),
37+
... has_status_details(with_message_contains("IndentationError"),
38+
... with_trace_contains("def test_broken():")
39+
... )
40+
... )
41+
... )
42+
"""
43+
raise IndentationError()
44+
45+
46+
def test_call_pytest_fail():
47+
"""
48+
>>> allure_report = getfixture('allure_report')
49+
>>> assert_that(allure_report,
50+
... has_test_case('test_call_pytest_fail',
51+
... with_status('failed'),
52+
... has_status_details(with_message_contains("Failed: <Failed instance>"),
53+
... with_trace_contains("def test_call_pytest_fail():")
54+
... )
55+
... )
56+
... )
57+
"""
58+
pytest.fail()
59+
60+
61+
def test_call_pytest_fail_with_reason():
62+
"""
63+
>>> allure_report = getfixture('allure_report')
64+
>>> assert_that(allure_report,
65+
... has_test_case('test_call_pytest_fail_with_reason',
66+
... with_status('failed'),
67+
... has_status_details(with_message_contains("Fail message"),
68+
... with_trace_contains("def test_call_pytest_fail():")
69+
... )
70+
... )
71+
... )
72+
"""
73+
pytest.fail("Fail message")
74+
Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,140 @@
1+
import pytest
2+
3+
4+
@pytest.fixture
5+
def failed_fixture():
6+
assert False
7+
8+
9+
def test_failed_fixture(failed_fixture):
10+
"""
11+
>>> allure_report = getfixture('allure_report')
12+
>>> assert_that(allure_report,
13+
... has_test_case('test_failed_fixture',
14+
... with_status('failed'),
15+
... has_status_details(with_message_contains("AssertionError"),
16+
... with_trace_contains("def failed_fixture():")
17+
... ),
18+
... has_container(allure_report,
19+
... has_before('failed_fixture',
20+
... with_status('failed'),
21+
... has_status_details(with_message_contains("AssertionError"),
22+
... with_trace_contains("failed_fixture")
23+
... ),
24+
... ),
25+
... )
26+
... )
27+
... )
28+
"""
29+
pass
30+
31+
32+
@pytest.fixture
33+
def broken_fixture():
34+
raise IndexError
35+
36+
37+
def test_broken_fixture(broken_fixture):
38+
"""
39+
>>> allure_report = getfixture('allure_report')
40+
>>> assert_that(allure_report,
41+
... has_test_case('test_broken_fixture',
42+
... with_status('broken'),
43+
... has_status_details(with_message_contains("IndexError"),
44+
... with_trace_contains("def broken_fixture():")
45+
... ),
46+
... has_container(allure_report,
47+
... has_before('broken_fixture',
48+
... with_status('broken'),
49+
... has_status_details(with_message_contains("IndexError"),
50+
... with_trace_contains("broken_fixture")
51+
... ),
52+
... ),
53+
... )
54+
... )
55+
... )
56+
"""
57+
pass
58+
59+
60+
@pytest.fixture
61+
def skip_fixture():
62+
pytest.skip()
63+
64+
65+
def test_skip_fixture(skip_fixture):
66+
"""
67+
>>> allure_report = getfixture('allure_report')
68+
>>> assert_that(allure_report,
69+
... has_test_case('test_skip_fixture',
70+
... with_status('skipped'),
71+
... has_status_details(with_message_contains("Skipped: <Skipped instance>")),
72+
... has_container(allure_report,
73+
... has_before('skip_fixture',
74+
... with_status('skipped'),
75+
... has_status_details(with_message_contains("Skipped: <Skipped instance>"),
76+
... with_trace_contains("skip_fixture")
77+
... ),
78+
... ),
79+
... )
80+
... )
81+
... )
82+
"""
83+
84+
85+
@pytest.fixture
86+
def pytest_fail_fixture():
87+
pytest.fail()
88+
89+
90+
def test_pytest_fail_fixture(pytest_fail_fixture):
91+
"""
92+
>>> allure_report = getfixture('allure_report')
93+
>>> assert_that(allure_report,
94+
... has_test_case('test_pytest_fail_fixture',
95+
... with_status('failed'),
96+
... has_status_details(with_message_contains("Failed: <Failed instance>"),
97+
... with_trace_contains("def pytest_fail_fixture():")
98+
... ),
99+
... has_container(allure_report,
100+
... has_before('pytest_fail_fixture',
101+
... with_status('failed'),
102+
... has_status_details(with_message_contains("Failed: <Failed instance>"),
103+
... with_trace_contains("pytest_fail_fixture")
104+
... ),
105+
... ),
106+
... )
107+
... )
108+
... )
109+
"""
110+
pass
111+
112+
113+
@pytest.fixture
114+
def pytest_fail_with_reason_fixture():
115+
pytest.fail("Fail message")
116+
117+
118+
def test_pytest_fail_with_reason_fixture(pytest_fail_with_reason_fixture):
119+
"""
120+
>>> allure_report = getfixture('allure_report')
121+
>>> assert_that(allure_report,
122+
... has_test_case('test_pytest_fail_with_reason_fixture',
123+
... with_status('failed'),
124+
... has_status_details(with_message_contains("Fail message"),
125+
... with_trace_contains("def pytest_fail_with_reason_fixture():")
126+
... ),
127+
... has_container(allure_report,
128+
... has_before('pytest_fail_with_reason_fixture',
129+
... with_status('failed'),
130+
... has_status_details(with_message_contains("Fail message"),
131+
... with_trace_contains("pytest_fail_with_reason_fixture")
132+
... ),
133+
... ),
134+
... )
135+
... )
136+
... )
137+
"""
138+
pass
139+
140+

0 commit comments

Comments
 (0)