/
test_step_runner.py
300 lines (241 loc) · 9.74 KB
/
test_step_runner.py
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
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
# -*- coding: utf-8 -*-
# <Lettuce - Behaviour Driven Development for python>
# Copyright (C) <2010> Gabriel Falcão <gabriel@nacaolivre.org>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
from lettuce import step
from lettuce import after
from lettuce import core
from lettuce import registry
from lettuce.core import Step
from lettuce.core import Feature
from nose.tools import assert_equals, with_setup
FEATURE1 = """
Feature: Count steps ran
Scenario: Total of steps ran
Given I have a defined step
When other step fails
Then it won't reach here
Then I have a defined step
"""
FEATURE2 = """
Feature: Find undefined steps
Scenario: Undefined step can be pointed
Given I have a defined step
Then this one has no definition
And this one also
"""
FEATURE3 = """
Feature: Lettuce can ignore case
Scenario: On step definitions
Given I define a step
And DEFINE a STEP
And also define A sTeP
"""
FEATURE4 = '''
Feature: My steps are rocking!
Scenario: Step definition receive regex matched groups as parameters
Given a person called "John Doe"
'''
FEATURE5 = '''
Feature: My steps are rocking!
Scenario: Step definition receive regex matched named groups as parameters
When a foreign at "Rio de Janeiro"
'''
FEATURE6 = '''
Feature: My steps are rocking!
Scenario: Step definition receive regex matched named groups as parameters
Then he gets a caipirinha
'''
FEATURE7 = """
Feature: Many scenarios
Scenario: 1st one
Given I have a defined step
Scenario: 2nd one
Given I have a defined step
Scenario: 3rd one
Given I have a defined step
Scenario: 4th one
Given I have a defined step
Scenario: 5th one
Given I have a defined step
"""
FEATURE8 = """
Feature: Count step definitions with exceptions as failing steps
Scenario: Raising exception
Given I have a defined step
When I have a step that raises an exception
Then this step will be skipped
"""
def step_runner_environ():
"Make sure the test environment is what is expected"
from lettuce import registry
registry.clear()
@step('I have a defined step')
def have_a_defined_step(*args, **kw):
assert True
@step('other step fails')
def and_another(*args, **kw):
assert False, 'It should fail'
@step("define a step")
def define_a_step(*args, **kw):
assert True
@step(u'When I have a step that raises an exception')
def raises_exception(step):
raise Exception()
@with_setup(step_runner_environ)
def test_can_count_steps_and_its_states():
"The scenario result has the steps passed, failed and skipped steps. " \
"And total steps as well."
f = Feature.from_string(FEATURE1)
feature_result = f.run()
scenario_result = feature_result.scenario_results[0]
assert_equals(len(scenario_result.steps_passed), 1)
assert_equals(len(scenario_result.steps_failed), 1)
assert_equals(len(scenario_result.steps_undefined), 1)
assert_equals(len(scenario_result.steps_skipped), 1)
assert_equals(scenario_result.total_steps, 4)
@with_setup(step_runner_environ)
def test_can_point_undefined_steps():
"The scenario result has also the undefined steps."
f = Feature.from_string(FEATURE2)
feature_result = f.run()
scenario_result = feature_result.scenario_results[0]
assert_equals(len(scenario_result.steps_undefined), 2)
assert_equals(len(scenario_result.steps_passed), 1)
assert_equals(scenario_result.total_steps, 3)
undefined1 = scenario_result.steps_undefined[0]
undefined2 = scenario_result.steps_undefined[1]
assert_equals(undefined1.sentence, 'Then this one has no definition')
assert_equals(undefined2.sentence, 'And this one also')
@with_setup(step_runner_environ)
def test_can_figure_out_why_has_failed():
"It can figure out why the test has failed"
f = Feature.from_string(FEATURE1)
feature_result = f.run()
scenario_result = feature_result.scenario_results[0]
failed_step = scenario_result.steps_failed[0]
assert_equals(failed_step.why.cause, 'It should fail')
assert 'Traceback (most recent call last):' in failed_step.why.traceback
assert 'AssertionError: It should fail' in failed_step.why.traceback
assert_equals(type(failed_step.why.exception), AssertionError)
@with_setup(step_runner_environ)
def test_skipped_steps_can_be_retrieved_as_steps():
"Skipped steps can be retrieved as steps"
f = Feature.from_string(FEATURE1)
feature_result = f.run()
scenario_result = feature_result.scenario_results[0]
for step in scenario_result.steps_skipped:
assert_equals(type(step), Step)
@with_setup(step_runner_environ)
def test_ignore_case_on_step_definitions():
"By default lettuce ignore case on step definitions"
f = Feature.from_string(FEATURE3)
feature_result = f.run()
scenario_result = feature_result.scenario_results[0]
assert_equals(len(scenario_result.steps_passed), 3)
assert_equals(scenario_result.total_steps, 3)
assert all([s.has_definition for s in scenario_result.scenario.steps])
@with_setup(step_runner_environ)
def test_doesnt_ignore_case():
"Lettuce can, optionally consider case on step definitions"
f = Feature.from_string(FEATURE3)
feature_result = f.run(ignore_case=False)
scenario_result = feature_result.scenario_results[0]
assert_equals(len(scenario_result.steps_passed), 1)
assert_equals(len(scenario_result.steps_undefined), 2)
assert_equals(scenario_result.total_steps, 3)
assert not all([s.has_definition for s in scenario_result.scenario.steps])
@with_setup(step_runner_environ)
def test_steps_are_aware_of_its_definitions():
"Steps are aware of its definitions line numbers and file names"
f = Feature.from_string(FEATURE1)
feature_result = f.run()
scenario_result = feature_result.scenario_results[0]
for step in scenario_result.steps_passed:
assert step.has_definition
step1 = scenario_result.steps_passed[0]
assert_equals(step1.defined_at.line, 102)
assert_equals(step1.defined_at.file, core.fs.relpath(__file__.rstrip("c")))
@with_setup(step_runner_environ)
def test_steps_that_match_groups_takes_them_as_parameters():
"Steps that match groups takes them as parameters"
@step(r'Given a ([^\s]+) called "(.*)"')
def given_what_named(step, what, name):
assert_equals(what, 'person')
assert_equals(name, 'John Doe')
f = Feature.from_string(FEATURE4)
feature_result = f.run()
scenario_result = feature_result.scenario_results[0]
assert_equals(len(scenario_result.steps_passed), 1)
assert_equals(scenario_result.total_steps, 1)
@with_setup(step_runner_environ)
def test_steps_that_match_named_groups_takes_them_as_parameters():
"Steps that match named groups takes them as parameters"
@step(r'When a (?P<what>\w+) at "(?P<city>.*)"')
def given_action_named(step, what, city):
assert_equals(what, 'foreign')
assert_equals(city, 'Rio de Janeiro')
f = Feature.from_string(FEATURE5)
feature_result = f.run()
scenario_result = feature_result.scenario_results[0]
assert_equals(len(scenario_result.steps_passed), 1)
assert_equals(scenario_result.total_steps, 1)
@with_setup(step_runner_environ)
def test_steps_that_match_groups_and_named_groups_takes_just_named_as_params():
"Steps that match groups and named groups takes just the named as parameters"
@step(r'(he|she) gets a (?P<what>\w+)')
def given_action_named(step, what):
assert_equals(what, 'caipirinha')
f = Feature.from_string(FEATURE6)
feature_result = f.run()
scenario_result = feature_result.scenario_results[0]
assert_equals(len(scenario_result.steps_passed), 1)
assert_equals(scenario_result.total_steps, 1)
@with_setup(step_runner_environ)
def test_step_definitions_takes_the_step_object_as_first_argument():
"Step definitions takes step object as first argument"
FEATURE = '''
Feature: Steps as args
Scenario: Steps as args
When I define this one
'''
@step(r'When I define this one')
def when_i_define_this_one(step):
assert_equals(step.sentence, 'When I define this one')
f = Feature.from_string(FEATURE)
feature_result = f.run()
scenario_result = feature_result.scenario_results[0]
assert_equals(len(scenario_result.steps_passed), 1)
assert_equals(scenario_result.total_steps, 1)
@with_setup(step_runner_environ)
def test_feature_can_run_only_specified_scenarios():
"Features can run only specified scenarios, by index + 1"
feature = Feature.from_string(FEATURE7)
scenarios_ran = []
@after.each_scenario
def just_register(scenario):
scenarios_ran.append(scenario.name)
feature.run(scenarios=(2, 5))
assert_equals(scenarios_ran, ['2nd one', '5th one'])
@with_setup(step_runner_environ)
def test_count_raised_exceptions_as_failing_steps():
"When a step definition raises an exception, it is marked as a failed step. "
try:
f = Feature.from_string(FEATURE8)
feature_result = f.run()
scenario_result = feature_result.scenario_results[0]
assert_equals(len(scenario_result.steps_failed), 1)
finally:
registry.clear()