rspec-given 2.1.0.beta.4 → 2.1.0.beta.5
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile +0 -4
- data/Gemfile.lock +0 -2
- data/README +164 -122
- data/README.md +76 -58
- data/README.old +80 -62
- data/Rakefile +0 -1
- data/examples/{spec_helper.rb → example_helper.rb} +4 -3
- data/examples/integration/and_spec.rb +5 -4
- data/examples/integration/focused_line_spec.rb +1 -1
- data/examples/other/line_example.rb +1 -1
- data/examples/stack/stack_spec.rb +1 -1
- data/lib/rspec/given.rb +2 -1
- data/lib/rspec/given/extensions.rb +3 -3
- data/lib/rspec/given/file_cache.rb +19 -0
- data/lib/rspec/given/line_extractor.rb +43 -0
- data/lib/rspec/given/version.rb +1 -1
- metadata +27 -11
- data/lib/rspec/given/line_cache.rb +0 -34
data/README.old
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# rspec-given
|
2
2
|
|
3
|
-
Covering rspec-given, version 2.1.0.beta.
|
3
|
+
Covering rspec-given, version 2.1.0.beta.4.
|
4
4
|
|
5
5
|
rspec-given is an RSpec extension to allow Given/When/Then notation in
|
6
6
|
RSpec specifications. It is a natural extension of the experimental
|
@@ -23,7 +23,7 @@ _rspec-given_ is ready for production use.
|
|
23
23
|
|
24
24
|
Here is a specification written in the rspec-given framework:
|
25
25
|
|
26
|
-
|
26
|
+
```ruby
|
27
27
|
require 'rspec/given'
|
28
28
|
require 'spec_helper'
|
29
29
|
require 'stack'
|
@@ -46,7 +46,7 @@ describe Stack do
|
|
46
46
|
When { stack.push(:an_item) }
|
47
47
|
|
48
48
|
Then { stack.depth.should == 1 }
|
49
|
-
|
49
|
+
Then { stack.top.should == :an_item }
|
50
50
|
end
|
51
51
|
|
52
52
|
context "when popping" do
|
@@ -62,7 +62,7 @@ describe Stack do
|
|
62
62
|
When(:pop_result) { stack.pop }
|
63
63
|
|
64
64
|
Then { pop_result.should == :an_item }
|
65
|
-
|
65
|
+
Then { stack.depth.should == 0 }
|
66
66
|
end
|
67
67
|
end
|
68
68
|
|
@@ -81,12 +81,12 @@ describe Stack do
|
|
81
81
|
When(:pop_result) { stack.pop }
|
82
82
|
|
83
83
|
Then { pop_result.should == :top_item }
|
84
|
-
|
85
|
-
|
84
|
+
Then { stack.top.should == :second_item }
|
85
|
+
Then { stack.depth.should == original_depth - 1 }
|
86
86
|
end
|
87
87
|
end
|
88
88
|
end
|
89
|
-
|
89
|
+
```
|
90
90
|
|
91
91
|
Let's talk about the individual statements used in the Given
|
92
92
|
framework.
|
@@ -123,43 +123,44 @@ preconditions running before inner preconditions.
|
|
123
123
|
|
124
124
|
#### Given examples:
|
125
125
|
|
126
|
-
|
126
|
+
```ruby
|
127
127
|
Given(:stack) { Stack.new }
|
128
|
-
|
128
|
+
```
|
129
129
|
|
130
|
-
The given
|
131
|
-
test and the value of the block is bound to 'stack'.
|
132
|
-
reference to 'stack' in the specification will cause the
|
133
|
-
execute.
|
134
|
-
generated value.
|
130
|
+
The block for the given clause is lazily run if 'stack' is ever
|
131
|
+
referenced in the test and the value of the block is bound to 'stack'.
|
132
|
+
The first reference to 'stack' in the specification will cause the
|
133
|
+
code block to execute. Futher references to 'stack' will reuse the
|
134
|
+
previously generated value.
|
135
135
|
|
136
|
-
|
136
|
+
```ruby
|
137
137
|
Given!(:original_size) { stack.size }
|
138
|
-
|
138
|
+
```
|
139
139
|
|
140
140
|
The code block is run unconditionally once before each test and the
|
141
141
|
value of the block is bound to 'original_size'. This form is useful
|
142
142
|
when you want to record the value of something that might be affected
|
143
143
|
by the When code.
|
144
144
|
|
145
|
-
|
145
|
+
```ruby
|
146
146
|
Given { stack.clear }
|
147
|
-
|
147
|
+
```
|
148
148
|
|
149
|
-
The given
|
150
|
-
form of given is used for code that is executed for side
|
149
|
+
The block for the given clause is run unconditionally once before each
|
150
|
+
test. This form of given is used for code that is executed for side
|
151
|
+
effects.
|
151
152
|
|
152
153
|
### When
|
153
154
|
|
154
|
-
The _When_
|
155
|
+
The _When_ clause specifies the code to be tested ... oops, excuse me
|
155
156
|
... specified. After the preconditions in the given section are met,
|
156
157
|
the when code block is run.
|
157
158
|
|
158
|
-
There should
|
159
|
-
_When_ in an outer context shoud be treated as a
|
160
|
-
context.
|
159
|
+
There should not be more than one _When_ clause for a given direct
|
160
|
+
context. However, a _When_ in an outer context shoud be treated as a
|
161
|
+
_Given_ in an inner context. E.g.
|
161
162
|
|
162
|
-
|
163
|
+
```ruby
|
163
164
|
context "outer context" do
|
164
165
|
When { code specified in the outer context }
|
165
166
|
Then { assert something about the outer context }
|
@@ -173,30 +174,31 @@ context. E.g.
|
|
173
174
|
Then { assert something about the inner context }
|
174
175
|
end
|
175
176
|
end
|
176
|
-
|
177
|
+
```
|
177
178
|
|
178
179
|
#### When examples:
|
179
180
|
|
180
|
-
|
181
|
+
```ruby
|
181
182
|
When { stack.push(:item) }
|
182
|
-
|
183
|
+
```
|
183
184
|
|
184
185
|
The code block is executed once per test. The effect of the _When{}_
|
185
186
|
block is very similar to _Given{}_. However, When is used to identify
|
186
187
|
the particular code that is being specified in the current context or
|
187
188
|
describe block.
|
188
189
|
|
189
|
-
|
190
|
+
```ruby
|
190
191
|
When(:result) { stack.pop }
|
191
|
-
|
192
|
+
```
|
192
193
|
|
193
194
|
The code block is executed once per test and the value of the code
|
194
195
|
block is bound to 'result'. Use this form when the code under test
|
195
196
|
returns a value that you wish to interrogate in the _Then_ code.
|
196
197
|
|
197
|
-
If an exception occurs during the execution of the
|
198
|
-
exception is caught and a failure object is bound to
|
199
|
-
failure can be checked in a then block with the
|
198
|
+
If an exception occurs during the execution of the block for the When
|
199
|
+
clause, the exception is caught and a failure object is bound to
|
200
|
+
'result'. The failure can be checked in a then block with the
|
201
|
+
'have_failed' matcher.
|
200
202
|
|
201
203
|
The failure object will rethrow the captured exception if anything
|
202
204
|
other than have_failed matcher is used on the failure object.
|
@@ -205,10 +207,10 @@ For example, if the stack is empty when it is popped, then it is
|
|
205
207
|
reasonable for pop to raise an UnderflowError. This is how you might
|
206
208
|
specify that behavior:
|
207
209
|
|
208
|
-
|
210
|
+
```ruby
|
209
211
|
When(:result) { stack.pop }
|
210
212
|
Then { result.should have_failed(UnderflowError, /empty/) }
|
211
|
-
|
213
|
+
```
|
212
214
|
|
213
215
|
Note that the arguments to the 'have_failed' matcher are the same as
|
214
216
|
those given to the standard RSpec matcher 'raise_error'.
|
@@ -220,7 +222,13 @@ then conditions must be true after the code under test (the _When_
|
|
220
222
|
clause) is run.
|
221
223
|
|
222
224
|
The code in the block of a _Then_ clause should be a single _should_
|
223
|
-
assertion. Code in _Then_
|
225
|
+
assertion. Code in _Then_ clauses should not have any side effects.
|
226
|
+
|
227
|
+
Let me repeat that: <b>_Then_ clauses should not have any side
|
228
|
+
effects!</b> _Then_ clauses with side effects are erroneous. _Then_
|
229
|
+
clauses need to be idempotent, so that running them once, twice, a
|
230
|
+
hundred times, or never does not change the state of the program. (The
|
231
|
+
same is true of _And_ clauses).
|
224
232
|
|
225
233
|
In RSpec terms, a _Then_ clause forms a RSpec Example that runs in the
|
226
234
|
context of an Example Group (defined by a describe or context clause).
|
@@ -230,27 +238,28 @@ there will be no examples to be run for that group. If all the
|
|
230
238
|
assertions in an example group are done via Invariants, then the group
|
231
239
|
should use an empty _Then_ clause, like this:
|
232
240
|
|
233
|
-
|
241
|
+
```ruby
|
234
242
|
Then { }
|
235
|
-
|
243
|
+
```
|
236
244
|
|
237
245
|
#### Then examples:
|
238
246
|
|
239
|
-
|
247
|
+
```ruby
|
240
248
|
Then { stack.should be_empty }
|
241
|
-
|
249
|
+
```
|
242
250
|
|
243
|
-
After the related _When_
|
244
|
-
it is not empty, the test will fail.
|
251
|
+
After the related block for the _When_ clause is run, the stack should
|
252
|
+
be empty. If it is not empty, the test will fail.
|
245
253
|
|
246
254
|
### And
|
247
255
|
|
248
|
-
The _And_ clause is similar to _Then_, but
|
249
|
-
|
256
|
+
The _And_ clause is similar to _Then_, but does not form its own RSpec
|
257
|
+
example. This means that _And_ clauses reuse the setup from a sibling
|
250
258
|
_Then_ clause. Using a single _Then_ an multiple _And_ clauses in an
|
251
259
|
example group means the setup for that group is run only once (for the
|
252
|
-
_Then_ clause). This can be a
|
253
|
-
setup for an example group is
|
260
|
+
_Then_ clause) and reused for all the _And_s. This can be a
|
261
|
+
significant speed savings where the setup for an example group is
|
262
|
+
expensive.
|
254
263
|
|
255
264
|
Some things to keep in mind about _And_ clauses:
|
256
265
|
|
@@ -259,7 +268,7 @@ Some things to keep in mind about _And_ clauses:
|
|
259
268
|
is an error.
|
260
269
|
|
261
270
|
1. The code in the _And_ clause is run immediately after the first
|
262
|
-
_Then_ of an example group.
|
271
|
+
(executed) _Then_ of an example group.
|
263
272
|
|
264
273
|
1. And assertion failures in a _Then_ clause or a _And_ clause will
|
265
274
|
cause all the subsequent _And_ clauses to be skipped.
|
@@ -270,6 +279,10 @@ Some things to keep in mind about _And_ clauses:
|
|
270
279
|
appear in the documentation, html or textmate formats (options
|
271
280
|
-fhtml, -fdoc, or -ftextmate).
|
272
281
|
|
282
|
+
1. Like _Then_ clauses, _And_ clauses must be idempotent. That means
|
283
|
+
they should not execute any code that changes global program state.
|
284
|
+
(See the section on the _Then_ clause).
|
285
|
+
|
273
286
|
The choice to use an _And_ clause is primarily a speed consideration.
|
274
287
|
If an example group has expensive setup and there are a lot of _Then_
|
275
288
|
clauses, then choosing to make some of the _Then_ clauses into _And_
|
@@ -278,26 +291,27 @@ stick with _Then_ clauses.
|
|
278
291
|
|
279
292
|
#### Then/And examples:
|
280
293
|
|
281
|
-
|
294
|
+
```ruby
|
282
295
|
Then { pop_result.should == :top_item } # Required
|
283
296
|
And { stack.top.should == :second_item } # No Setup rerun
|
284
297
|
And { stack.depth.should == original_depth - 1 } # ... for these
|
285
|
-
|
298
|
+
```
|
286
299
|
|
287
300
|
### Invariant
|
288
301
|
|
289
|
-
The _Invariant_
|
290
|
-
RSpec or Test::Unit.
|
291
|
-
|
292
|
-
|
293
|
-
<tt>
|
294
|
-
<tt>empty?</tt> should be
|
302
|
+
The _Invariant_ clause is a new idea that doesn't have an analog in
|
303
|
+
RSpec or Test::Unit. The invariant allows you specify things that must
|
304
|
+
always be true (or at least always be true in the scope of the
|
305
|
+
invariant). In the stack example, <tt>empty?</tt> is defined in term
|
306
|
+
of <tt>size</tt>. Whenever <tt>size</tt> is 0, <tt>empty?</tt> should
|
307
|
+
be true. Whenever <tt>size</tt> is non-zero, <tt>empty?</tt> should be
|
308
|
+
false.
|
295
309
|
|
296
|
-
You can conceptually think of an _Invariant_
|
310
|
+
You can conceptually think of an _Invariant_ clause as a _Then_ block
|
297
311
|
that automatically gets added to every _Then_ within its scope.
|
298
312
|
|
299
|
-
Invariants nested within a context only apply to the _Then_
|
300
|
-
that context.
|
313
|
+
Invariants nested within a context only apply to the _Then_ clauses
|
314
|
+
that are in the scope of that context.
|
301
315
|
|
302
316
|
Invariants that reference a _Given_ precondition accessor must only be
|
303
317
|
used in contexts that define that accessor.
|
@@ -319,9 +333,9 @@ the examples to produce better looking output. If you don't care about
|
|
319
333
|
the pretty output and wish to disable source code caching
|
320
334
|
unconditionally, then add the following line to your spec helper file:
|
321
335
|
|
322
|
-
|
336
|
+
```ruby
|
323
337
|
RSpec::Given.source_caching_disabled = true
|
324
|
-
|
338
|
+
```
|
325
339
|
|
326
340
|
# Future Directions
|
327
341
|
|
@@ -329,14 +343,18 @@ I really like the way the Given framework is working out. I feel my
|
|
329
343
|
tests are much more like specifications when I use it. However, I'm
|
330
344
|
not entirely happy with it.
|
331
345
|
|
332
|
-
I would like to remove the need for the ".should" in all the
|
333
|
-
|
346
|
+
I would like to remove the need for the ".should" in all the _Then_
|
347
|
+
clauses. In other words, instead of saying:
|
334
348
|
|
349
|
+
```ruby
|
335
350
|
Then { x.should == y }
|
351
|
+
```
|
336
352
|
|
337
353
|
we could say:
|
338
354
|
|
355
|
+
```ruby
|
339
356
|
Then { x == y }
|
357
|
+
```
|
340
358
|
|
341
359
|
I think the [wrong assertion library](http://rubygems.org/gems/wrong)
|
342
360
|
has laid some groundwork in this area.
|
data/Rakefile
CHANGED
@@ -1,16 +1,17 @@
|
|
1
1
|
require 'rspec/given'
|
2
|
-
require '
|
2
|
+
require 'example_helper'
|
3
3
|
|
4
4
|
describe "And" do
|
5
|
+
|
5
6
|
Given(:info) { [] }
|
6
|
-
Given(:mock) { flexmock("mock") }
|
7
7
|
|
8
8
|
describe "And is called after Then" do
|
9
|
-
Given { mock
|
9
|
+
Given(:m) { mock("mock") }
|
10
|
+
Given { m.should_receive(:and_ran) }
|
10
11
|
Then { info << "T" }
|
11
12
|
And {
|
12
13
|
info.should == ["T"]
|
13
|
-
|
14
|
+
m.and_ran
|
14
15
|
}
|
15
16
|
end
|
16
17
|
|
data/lib/rspec/given.rb
CHANGED
@@ -14,7 +14,8 @@ if RSpec::Given.using_old_rspec?
|
|
14
14
|
else
|
15
15
|
require 'rspec/given/version'
|
16
16
|
require 'rspec/given/module_methods'
|
17
|
-
require 'rspec/given/
|
17
|
+
require 'rspec/given/file_cache'
|
18
|
+
require 'rspec/given/line_extractor'
|
18
19
|
require 'rspec/given/extensions'
|
19
20
|
require 'rspec/given/configure'
|
20
21
|
require 'rspec/given/failure'
|
@@ -71,8 +71,8 @@ module RSpec
|
|
71
71
|
@_rg_contet_info ||= {}
|
72
72
|
end
|
73
73
|
|
74
|
-
def
|
75
|
-
@
|
74
|
+
def _rg_lines
|
75
|
+
@_rg_lines ||= LineExtractor.new
|
76
76
|
end
|
77
77
|
|
78
78
|
# Trigger the evaluation of a Given! block by referencing its
|
@@ -166,7 +166,7 @@ module RSpec
|
|
166
166
|
b = block.binding
|
167
167
|
file = eval "__FILE__", b
|
168
168
|
line = eval "__LINE__", b
|
169
|
-
description =
|
169
|
+
description = _rg_lines.line(file, line) unless RSpec::Given.source_caching_disabled
|
170
170
|
if description
|
171
171
|
cmd = "it(description)"
|
172
172
|
else
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module RSpec
|
2
|
+
module Given
|
3
|
+
class FileCache
|
4
|
+
def initialize
|
5
|
+
@lines = {}
|
6
|
+
end
|
7
|
+
|
8
|
+
def get(file_name)
|
9
|
+
@lines[file_name] ||= read_lines(file_name)
|
10
|
+
end
|
11
|
+
|
12
|
+
private
|
13
|
+
|
14
|
+
def read_lines(file_name)
|
15
|
+
open(file_name) { |f| f.readlines }
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
require 'rspec/given/file_cache'
|
2
|
+
|
3
|
+
module RSpec
|
4
|
+
module Given
|
5
|
+
class LineExtractor
|
6
|
+
def initialize(file_cache=nil)
|
7
|
+
@files = file_cache || FileCache.new
|
8
|
+
end
|
9
|
+
|
10
|
+
def line(file_name, line)
|
11
|
+
lines = @files.get(file_name)
|
12
|
+
extract_lines_from(lines, line-1)
|
13
|
+
end
|
14
|
+
|
15
|
+
def to_s
|
16
|
+
"<LineExtractor>"
|
17
|
+
end
|
18
|
+
|
19
|
+
private
|
20
|
+
|
21
|
+
def extract_lines_from(lines, line_index)
|
22
|
+
result = lines[line_index]
|
23
|
+
if continued?(result)
|
24
|
+
level = indentation_level(result)
|
25
|
+
begin
|
26
|
+
line_index += 1
|
27
|
+
result << lines[line_index]
|
28
|
+
end while indentation_level(lines[line_index]) > level
|
29
|
+
end
|
30
|
+
result
|
31
|
+
end
|
32
|
+
|
33
|
+
def continued?(string)
|
34
|
+
string =~ /(\{|do) *$/
|
35
|
+
end
|
36
|
+
|
37
|
+
def indentation_level(string)
|
38
|
+
string =~ /^(\s*)\S/
|
39
|
+
$1.size
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|