-
Notifications
You must be signed in to change notification settings - Fork 240
Expand file tree
/
Copy pathreporting.py
More file actions
193 lines (149 loc) · 6 KB
/
reporting.py
File metadata and controls
193 lines (149 loc) · 6 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
"""Reporting functionality.
Collection of the scenario excecution statuses, timing and other information
that enriches the pytest test reporting.
"""
import time
from .feature import force_unicode
from .utils import get_parametrize_markers_args, get_parametrize_params
class StepReport(object):
"""Step excecution report."""
failed = False
stopped = None
def __init__(self, step):
"""Step report constructor.
:param pytest_bdd.feature.Step step: Step.
"""
self.step = step
self.started = time.time()
def serialize(self):
"""Serialize the step excecution report.
:return: Serialized step excecution report.
:rtype: dict
"""
return {
"name": self.step.name,
"type": self.step.type,
"keyword": self.step.keyword,
"line_number": self.step.line_number,
"failed": self.failed,
"duration": self.duration,
}
def finalize(self, failed):
"""Stop collecting information and finalize the report.
:param bool failed: Wheither the step excecution is failed.
"""
self.stopped = time.time()
self.failed = failed
@property
def duration(self):
"""Step excecution duration.
:return: Step excecution duration.
:rtype: float
"""
if self.stopped is None:
return 0
return self.stopped - self.started
class ScenarioReport(object):
"""Scenario execution report."""
def __init__(self, scenario, node):
"""Scenario report constructor.
:param pytest_bdd.feature.Scenario scenario: Scenario.
:param node: pytest test node object
"""
self.scenario = scenario
self.step_reports = []
parametrize_args = get_parametrize_markers_args(node)
params = get_parametrize_params(parametrize_args)
self.param_index = self.get_param_index(node, params)
self.example_kwargs = self.get_example_kwargs(node, params)
def get_param_index(self, node, params):
if params:
param_names = params[0]['names']
param_values = params[0]['values']
node_param_values = [node.funcargs[param_name] for param_name in param_names]
if node_param_values in param_values:
return param_values.index(node_param_values)
elif tuple(node_param_values) in param_values:
return param_values.index(tuple(node_param_values))
return None
def get_example_kwargs(self, node, params):
params_names = (param['names'] for param in params)
all_names = sum(params_names, [])
return {
example_param_name: force_unicode(node.funcargs[example_param_name])
for example_param_name in all_names
}
@property
def current_step_report(self):
"""Get current step report.
:return: Last or current step report.
:rtype: pytest_bdd.reporting.StepReport
"""
return self.step_reports[-1]
def add_step_report(self, step_report):
"""Add new step report.
:param step_report: New current step report.
:type step_report: pytest_bdd.reporting.StepReport
"""
self.step_reports.append(step_report)
def serialize(self):
"""Serialize scenario excecution report in order to transfer reportin from nodes in the distributed mode.
:return: Serialized report.
:rtype: dict
"""
scenario = self.scenario
feature = scenario.feature
params = sum(scenario.get_params(builtin=True), []) if scenario.examples else None
return {
"steps": [step_report.serialize() for step_report in self.step_reports],
"name": scenario.name,
"line_number": scenario.line_number,
"tags": sorted(scenario.tags),
"feature": {
"name": feature.name,
"filename": feature.filename,
"rel_filename": feature.rel_filename,
"line_number": feature.line_number,
"description": feature.description,
"tags": sorted(feature.tags),
},
"examples": [
{
"name": scenario.examples.name,
"line_number": scenario.examples.line_number,
"rows": params,
"row_index": self.param_index,
}
] if scenario.examples else [],
"example_kwargs": self.example_kwargs,
}
def fail(self):
"""Stop collecting information and finalize the report as failed."""
self.current_step_report.finalize(failed=True)
remaining_steps = self.scenario.steps[len(self.step_reports):]
# Fail the rest of the steps and make reports.
for step in remaining_steps:
report = StepReport(step=step)
report.finalize(failed=True)
self.add_step_report(report)
def runtest_makereport(item, call, rep):
"""Store item in the report object."""
try:
scenario_report = item.__scenario_report__
except AttributeError:
pass
else:
rep.scenario = scenario_report.serialize()
rep.item = {"name": item.name}
def before_scenario(request, feature, scenario):
"""Create scenario report for the item."""
request.node.__scenario_report__ = ScenarioReport(scenario=scenario, node=request.node)
def step_error(request, feature, scenario, step, step_func, step_func_args, exception):
"""Finalize the step report as failed."""
request.node.__scenario_report__.fail()
def before_step(request, feature, scenario, step, step_func):
"""Store step start time."""
request.node.__scenario_report__.add_step_report(StepReport(step=step))
def after_step(request, feature, scenario, step, step_func, step_func_args):
"""Finalize the step report as successful."""
request.node.__scenario_report__.current_step_report.finalize(failed=False)