rspec-given 2.1.0.beta.4 → 2.1.0.beta.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|