rspec-given 2.1.0.beta.1 → 2.1.0.beta.4

Sign up to get free protection for your applications and to get access to all the features.
data/README ADDED
@@ -0,0 +1,325 @@
1
+ = rspec-given
2
+
3
+ Covering rspec-given, version 2.1.0.beta.4.
4
+
5
+ rspec-given is an RSpec extension to allow Given/When/Then notation in
6
+ RSpec specifications. It is a natural extension of the experimental
7
+ work done on the Given framework. It turns out that 90% of the Given
8
+ framework can be trivially implemented on top of RSpec.
9
+
10
+ = Why Given/When/Then
11
+
12
+ RSpec has done a great job of making specifications more readable for
13
+ humans. However, I really like the given / when / then nature of
14
+ Cucumber stories and would like to follow the same structure in my
15
+ unit tests. rspec-given allows a simple given/when/then structure
16
+ RSpec specifications.
17
+
18
+ == Status
19
+
20
+ _rspec-given_ is ready for production use.
21
+
22
+ == Example
23
+
24
+ Here is a specification written in the rspec-given framework:
25
+
26
+ require 'rspec/given'
27
+ require 'spec_helper'
28
+ require 'stack'
29
+
30
+ describe Stack do
31
+ def stack_with(initial_contents)
32
+ stack = Stack.new
33
+ initial_contents.each do |item| stack.push(item) end
34
+ stack
35
+ end
36
+
37
+ Given(:stack) { stack_with(initial_contents) }
38
+ Invariant { stack.empty?.should == (stack.depth == 0) }
39
+
40
+ context "when empty" do
41
+ Given(:initial_contents) { [] }
42
+ Then { stack.depth.should == 0 }
43
+
44
+ context "when pushing" do
45
+ When { stack.push(:an_item) }
46
+
47
+ Then { stack.depth.should == 1 }
48
+ Then { stack.top.should == :an_item }
49
+ end
50
+
51
+ context "when popping" do
52
+ When(:result) { stack.pop }
53
+ Then { result.should have_failed(Stack::UnderflowError, /empty/) }
54
+ end
55
+ end
56
+
57
+ context "with one item" do
58
+ Given(:initial_contents) { [:an_item] }
59
+
60
+ context "when popping" do
61
+ When(:pop_result) { stack.pop }
62
+
63
+ Then { pop_result.should == :an_item }
64
+ Then { stack.depth.should == 0 }
65
+ end
66
+ end
67
+
68
+ context "with several items" do
69
+ Given(:initial_contents) { [:second_item, :top_item] }
70
+ Given!(:original_depth) { stack.depth }
71
+
72
+ context "when pushing" do
73
+ When { stack.push(:new_item) }
74
+
75
+ Then { stack.top.should == :new_item }
76
+ Then { stack.depth.should == original_depth + 1 }
77
+ end
78
+
79
+ context "when popping" do
80
+ When(:pop_result) { stack.pop }
81
+
82
+ Then { pop_result.should == :top_item }
83
+ Then { stack.top.should == :second_item }
84
+ Then { stack.depth.should == original_depth - 1 }
85
+ end
86
+ end
87
+ end
88
+
89
+ Let's talk about the individual statements used in the Given
90
+ framework.
91
+
92
+ === Given
93
+
94
+ The _Given_ section specifies a starting point, a set of preconditions
95
+ that must be true before the code under test is allowed to be run. In
96
+ standard test frameworks the preconditions are established with a
97
+ combination of setup methods (or :before actions in RSpec) and code in
98
+ the test.
99
+
100
+ In the example code above the preconditions are started with _Given_
101
+ statements. A top level _Given_ (that applies to the entire describe
102
+ block) says that one of the preconditions is that there is a stack
103
+ with some initial contents.
104
+
105
+ Note that initial contents are not specified in the top level describe
106
+ block, but are given in each of the nested contexts. By pushing the
107
+ definition of "initial_contents" into the nested contexts, we can vary
108
+ them as needed for that particular context.
109
+
110
+ A precondition in the form "Given(:var) {...}" creates an accessor
111
+ method named "var". The accessor is lazily initialized by the code
112
+ block. If you want a non-lazy given, use "Given!(:var) {...}".
113
+
114
+ A precondition in the form "Given {...}" just executes the code block
115
+ for side effects. Since there is no accessor, the code block is
116
+ executed immediately (i.e. no lazy evaluation).
117
+
118
+ The preconditions are run in order of definition. Nested contexts
119
+ will inherit the preconditions from the enclosing context, with out
120
+ preconditions running before inner preconditions.
121
+
122
+ ==== Given examples:
123
+
124
+ Given(:stack) { Stack.new }
125
+
126
+ The given block is lazily run if 'stack' is ever referenced in the
127
+ test and the value of the block is bound to 'stack'. The first
128
+ reference to 'stack' in the specification will cause the code block to
129
+ execute. Futher references to 'stack' will reuse the previously
130
+ generated value.
131
+
132
+ Given!(:original_size) { stack.size }
133
+
134
+ The code block is run unconditionally once before each test and the
135
+ value of the block is bound to 'original_size'. This form is useful
136
+ when you want to record the value of something that might be affected
137
+ by the When code.
138
+
139
+ Given { stack.clear }
140
+
141
+ The given block is run unconditionally once before each test. This
142
+ form of given is used for code that is executed for side effects.
143
+
144
+ === When
145
+
146
+ The _When_ block specifies the code to be tested ... oops, excuse me
147
+ ... specified. After the preconditions in the given section are met,
148
+ the when code block is run.
149
+
150
+ There should only be one _When_ block for a given context. However, a
151
+ _When_ in an outer context shoud be treated as a _Given_ in an inner
152
+ context. E.g.
153
+
154
+ context "outer context" do
155
+ When { code specified in the outer context }
156
+ Then { assert something about the outer context }
157
+
158
+ context "inner context" do
159
+
160
+ # At this point, the _When_ of the outer context
161
+ # should be treated as a _Given_ of the inner context
162
+
163
+ When { code specified in the inner context }
164
+ Then { assert something about the inner context }
165
+ end
166
+ end
167
+
168
+ ==== When examples:
169
+
170
+ When { stack.push(:item) }
171
+
172
+ The code block is executed once per test. The effect of the _When{}_
173
+ block is very similar to _Given{}_. However, When is used to identify
174
+ the particular code that is being specified in the current context or
175
+ describe block.
176
+
177
+ When(:result) { stack.pop }
178
+
179
+ The code block is executed once per test and the value of the code
180
+ block is bound to 'result'. Use this form when the code under test
181
+ returns a value that you wish to interrogate in the _Then_ code.
182
+
183
+ If an exception occurs during the execution of the When block, the
184
+ exception is caught and a failure object is bound to 'result'. The
185
+ failure can be checked in a then block with the 'have_failed' matcher.
186
+
187
+ The failure object will rethrow the captured exception if anything
188
+ other than have_failed matcher is used on the failure object.
189
+
190
+ For example, if the stack is empty when it is popped, then it is
191
+ reasonable for pop to raise an UnderflowError. This is how you might
192
+ specify that behavior:
193
+
194
+ When(:result) { stack.pop }
195
+ Then { result.should have_failed(UnderflowError, /empty/) }
196
+
197
+ Note that the arguments to the 'have_failed' matcher are the same as
198
+ those given to the standard RSpec matcher 'raise_error'.
199
+
200
+ === Then
201
+
202
+ The _Then_ clauses are the postconditions of the specification. These
203
+ then conditions must be true after the code under test (the _When_
204
+ clause) is run.
205
+
206
+ The code in the block of a _Then_ clause should be a single _should_
207
+ assertion. Code in _Then_ blocks should not have any side effects.
208
+
209
+ In RSpec terms, a _Then_ clause forms a RSpec Example that runs in the
210
+ context of an Example Group (defined by a describe or context clause).
211
+
212
+ Each Example Group must have at least one _Then_ clause, otherwise
213
+ there will be no examples to be run for that group. If all the
214
+ assertions in an example group are done via Invariants, then the group
215
+ should use an empty _Then_ clause, like this:
216
+
217
+ Then { }
218
+
219
+ ==== Then examples:
220
+
221
+ Then { stack.should be_empty }
222
+
223
+ After the related _When_ block is run, the stack should be empty. If
224
+ it is not empty, the test will fail.
225
+
226
+ === And
227
+
228
+ The _And_ clause is similar to _Then_, but do not form their own RSpec
229
+ examples. This means that _And_ clauses reuse the setup from the
230
+ _Then_ clause. Using a single _Then_ an multiple _And_ clauses in an
231
+ example group means the setup for that group is run only once (for the
232
+ _Then_ clause). This can be a significant speed savings where the
233
+ setup for an example group is expensive.
234
+
235
+ Some things to keep in mind about _And_ clauses:
236
+
237
+ 1. There must be at least one _Then_ in the example group and it must
238
+ be declared before the _And_ clauses. Forgetting the _Then_ clause
239
+ is an error.
240
+
241
+ 1. The code in the _And_ clause is run immediately after the first
242
+ _Then_ of an example group.
243
+
244
+ 1. And assertion failures in a _Then_ clause or a _And_ clause will
245
+ cause all the subsequent _And_ clauses to be skipped.
246
+
247
+ 1. Since _And_ clauses do not form their own RSpec examples, they are
248
+ not represented in the formatted output of RSpec. That means _And_
249
+ clauses do not produce dots in the Progress format, nor do they
250
+ appear in the documentation, html or textmate formats (options
251
+ -fhtml, -fdoc, or -ftextmate).
252
+
253
+ The choice to use an _And_ clause is primarily a speed consideration.
254
+ If an example group has expensive setup and there are a lot of _Then_
255
+ clauses, then choosing to make some of the _Then_ clauses into _And_
256
+ clause will speed up the spec. Otherwise it is probably better to
257
+ stick with _Then_ clauses.
258
+
259
+ ==== Then/And examples:
260
+
261
+ Then { pop_result.should == :top_item } # Required
262
+ And { stack.top.should == :second_item } # No Setup rerun
263
+ And { stack.depth.should == original_depth - 1 } # ... for these
264
+
265
+ === Invariant
266
+
267
+ The _Invariant_ block is a new idea that doesn't have an analog in
268
+ RSpec or Test::Unit. The invariant allows you specify things that
269
+ must always be true. In the stack example, <tt>empty?</tt> is defined
270
+ in term of <tt>size</tt>. Whenever <tt>size</tt> is 0,
271
+ <tt>empty?</tt> should be true. Whenever <tt>size</tt> is non-zero,
272
+ <tt>empty?</tt> should be false.
273
+
274
+ You can conceptually think of an _Invariant_ block as a _Then_ block
275
+ that automatically gets added to every _Then_ within its scope.
276
+
277
+ Invariants nested within a context only apply to the _Then_ blocks in
278
+ that context.
279
+
280
+ Invariants that reference a _Given_ precondition accessor must only be
281
+ used in contexts that define that accessor.
282
+
283
+ Notes:
284
+
285
+ 1. Since Invariants do not form their own RSpec example, they are not
286
+ represented in the RSpec formatted output (e.g. the '--format html'
287
+ option).
288
+
289
+ == Configuration
290
+
291
+ Just require 'rspec/given' in the spec helper of your project and it
292
+ is ready to go.
293
+
294
+ If the RSpec format option document, html or textmate are chosen,
295
+ RSpec/Given will automatically add addition source code information to
296
+ the examples to produce better looking output. If you don't care about
297
+ the pretty output and wish to disable source code caching
298
+ unconditionally, then add the following line to your spec helper file:
299
+
300
+ RSpec::Given.source_caching_disabled = true
301
+
302
+ = Future Directions
303
+
304
+ I really like the way the Given framework is working out. I feel my
305
+ tests are much more like specifications when I use it. However, I'm
306
+ not entirely happy with it.
307
+
308
+ I would like to remove the need for the ".should" in all the
309
+ _Then_ blocks. In other words, instead of saying:
310
+
311
+ Then { x.should == y }
312
+
313
+ we could say:
314
+
315
+ Then { x == y }
316
+
317
+ I think the [wrong assertion library](http://rubygems.org/gems/wrong)
318
+ has laid some groundwork in this area.
319
+
320
+ = Links
321
+
322
+ * Github: [https://github.com/jimweirich/rspec-given](https://github.com/jimweirich/rspec-given)
323
+ * Clone URL: git://github.com/jimweirich/rspec-given.git
324
+ * Bug/Issue Reporting: [https://github.com/jimweirich/rspec-given/issues](https://github.com/jimweirich/rspec-given/issues)
325
+ * Continuous Integration: [http://travis-ci.org/#!/jimweirich/rspec-given](http://travis-ci.org/#!/jimweirich/rspec-given)
data/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # rspec-given
2
2
 
3
- Covering rspec-given, version 2.1.0.beta.1.
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
@@ -46,7 +46,7 @@ describe Stack do
46
46
  When { stack.push(:an_item) }
47
47
 
48
48
  Then { stack.depth.should == 1 }
49
- Also { stack.top.should == :an_item }
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
- Also { stack.depth.should == 0 }
65
+ Then { stack.depth.should == 0 }
66
66
  end
67
67
  end
68
68
 
@@ -215,13 +215,25 @@ those given to the standard RSpec matcher 'raise_error'.
215
215
 
216
216
  ### Then
217
217
 
218
- The _Then_ sections are the postconditions of the specification. These
218
+ The _Then_ clauses are the postconditions of the specification. These
219
219
  then conditions must be true after the code under test (the _When_
220
- block) is run.
220
+ clause) is run.
221
221
 
222
- The code in the _Then_ block should be a single _should_
222
+ The code in the block of a _Then_ clause should be a single _should_
223
223
  assertion. Code in _Then_ blocks should not have any side effects.
224
224
 
225
+ In RSpec terms, a _Then_ clause forms a RSpec Example that runs in the
226
+ context of an Example Group (defined by a describe or context clause).
227
+
228
+ Each Example Group must have at least one _Then_ clause, otherwise
229
+ there will be no examples to be run for that group. If all the
230
+ assertions in an example group are done via Invariants, then the group
231
+ should use an empty _Then_ clause, like this:
232
+
233
+ <pre>
234
+ Then { }
235
+ </pre>
236
+
225
237
  #### Then examples:
226
238
 
227
239
  <pre>
@@ -231,6 +243,47 @@ assertion. Code in _Then_ blocks should not have any side effects.
231
243
  After the related _When_ block is run, the stack should be empty. If
232
244
  it is not empty, the test will fail.
233
245
 
246
+ ### And
247
+
248
+ The _And_ clause is similar to _Then_, but do not form their own RSpec
249
+ examples. This means that _And_ clauses reuse the setup from the
250
+ _Then_ clause. Using a single _Then_ an multiple _And_ clauses in an
251
+ example group means the setup for that group is run only once (for the
252
+ _Then_ clause). This can be a significant speed savings where the
253
+ setup for an example group is expensive.
254
+
255
+ Some things to keep in mind about _And_ clauses:
256
+
257
+ 1. There must be at least one _Then_ in the example group and it must
258
+ be declared before the _And_ clauses. Forgetting the _Then_ clause
259
+ is an error.
260
+
261
+ 1. The code in the _And_ clause is run immediately after the first
262
+ _Then_ of an example group.
263
+
264
+ 1. And assertion failures in a _Then_ clause or a _And_ clause will
265
+ cause all the subsequent _And_ clauses to be skipped.
266
+
267
+ 1. Since _And_ clauses do not form their own RSpec examples, they are
268
+ not represented in the formatted output of RSpec. That means _And_
269
+ clauses do not produce dots in the Progress format, nor do they
270
+ appear in the documentation, html or textmate formats (options
271
+ -fhtml, -fdoc, or -ftextmate).
272
+
273
+ The choice to use an _And_ clause is primarily a speed consideration.
274
+ If an example group has expensive setup and there are a lot of _Then_
275
+ clauses, then choosing to make some of the _Then_ clauses into _And_
276
+ clause will speed up the spec. Otherwise it is probably better to
277
+ stick with _Then_ clauses.
278
+
279
+ #### Then/And examples:
280
+
281
+ <pre>
282
+ Then { pop_result.should == :top_item } # Required
283
+ And { stack.top.should == :second_item } # No Setup rerun
284
+ And { stack.depth.should == original_depth - 1 } # ... for these
285
+ </pre>
286
+
234
287
  ### Invariant
235
288
 
236
289
  The _Invariant_ block is a new idea that doesn't have an analog in
@@ -249,6 +302,27 @@ that context.
249
302
  Invariants that reference a _Given_ precondition accessor must only be
250
303
  used in contexts that define that accessor.
251
304
 
305
+ Notes:
306
+
307
+ 1. Since Invariants do not form their own RSpec example, they are not
308
+ represented in the RSpec formatted output (e.g. the '--format html'
309
+ option).
310
+
311
+ ## Configuration
312
+
313
+ Just require 'rspec/given' in the spec helper of your project and it
314
+ is ready to go.
315
+
316
+ If the RSpec format option document, html or textmate are chosen,
317
+ RSpec/Given will automatically add addition source code information to
318
+ the examples to produce better looking output. If you don't care about
319
+ the pretty output and wish to disable source code caching
320
+ unconditionally, then add the following line to your spec helper file:
321
+
322
+ <pre>
323
+ RSpec::Given.source_caching_disabled = true
324
+ </pre>
325
+
252
326
  # Future Directions
253
327
 
254
328
  I really like the way the Given framework is working out. I feel my
data/README.old ADDED
@@ -0,0 +1,349 @@
1
+ # rspec-given
2
+
3
+ Covering rspec-given, version 2.1.0.beta.3.
4
+
5
+ rspec-given is an RSpec extension to allow Given/When/Then notation in
6
+ RSpec specifications. It is a natural extension of the experimental
7
+ work done on the Given framework. It turns out that 90% of the Given
8
+ framework can be trivially implemented on top of RSpec.
9
+
10
+ # Why Given/When/Then
11
+
12
+ RSpec has done a great job of making specifications more readable for
13
+ humans. However, I really like the given / when / then nature of
14
+ Cucumber stories and would like to follow the same structure in my
15
+ unit tests. rspec-given allows a simple given/when/then structure
16
+ RSpec specifications.
17
+
18
+ ## Status
19
+
20
+ _rspec-given_ is ready for production use.
21
+
22
+ ## Example
23
+
24
+ Here is a specification written in the rspec-given framework:
25
+
26
+ <pre>
27
+ require 'rspec/given'
28
+ require 'spec_helper'
29
+ require 'stack'
30
+
31
+ describe Stack do
32
+ def stack_with(initial_contents)
33
+ stack = Stack.new
34
+ initial_contents.each do |item| stack.push(item) end
35
+ stack
36
+ end
37
+
38
+ Given(:stack) { stack_with(initial_contents) }
39
+ Invariant { stack.empty?.should == (stack.depth == 0) }
40
+
41
+ context "when empty" do
42
+ Given(:initial_contents) { [] }
43
+ Then { stack.depth.should == 0 }
44
+
45
+ context "when pushing" do
46
+ When { stack.push(:an_item) }
47
+
48
+ Then { stack.depth.should == 1 }
49
+ And { stack.top.should == :an_item }
50
+ end
51
+
52
+ context "when popping" do
53
+ When(:result) { stack.pop }
54
+ Then { result.should have_failed(Stack::UnderflowError, /empty/) }
55
+ end
56
+ end
57
+
58
+ context "with one item" do
59
+ Given(:initial_contents) { [:an_item] }
60
+
61
+ context "when popping" do
62
+ When(:pop_result) { stack.pop }
63
+
64
+ Then { pop_result.should == :an_item }
65
+ And { stack.depth.should == 0 }
66
+ end
67
+ end
68
+
69
+ context "with several items" do
70
+ Given(:initial_contents) { [:second_item, :top_item] }
71
+ Given!(:original_depth) { stack.depth }
72
+
73
+ context "when pushing" do
74
+ When { stack.push(:new_item) }
75
+
76
+ Then { stack.top.should == :new_item }
77
+ Then { stack.depth.should == original_depth + 1 }
78
+ end
79
+
80
+ context "when popping" do
81
+ When(:pop_result) { stack.pop }
82
+
83
+ Then { pop_result.should == :top_item }
84
+ And { stack.top.should == :second_item }
85
+ And { stack.depth.should == original_depth - 1 }
86
+ end
87
+ end
88
+ end
89
+ </pre>
90
+
91
+ Let's talk about the individual statements used in the Given
92
+ framework.
93
+
94
+ ### Given
95
+
96
+ The _Given_ section specifies a starting point, a set of preconditions
97
+ that must be true before the code under test is allowed to be run. In
98
+ standard test frameworks the preconditions are established with a
99
+ combination of setup methods (or :before actions in RSpec) and code in
100
+ the test.
101
+
102
+ In the example code above the preconditions are started with _Given_
103
+ statements. A top level _Given_ (that applies to the entire describe
104
+ block) says that one of the preconditions is that there is a stack
105
+ with some initial contents.
106
+
107
+ Note that initial contents are not specified in the top level describe
108
+ block, but are given in each of the nested contexts. By pushing the
109
+ definition of "initial_contents" into the nested contexts, we can vary
110
+ them as needed for that particular context.
111
+
112
+ A precondition in the form "Given(:var) {...}" creates an accessor
113
+ method named "var". The accessor is lazily initialized by the code
114
+ block. If you want a non-lazy given, use "Given!(:var) {...}".
115
+
116
+ A precondition in the form "Given {...}" just executes the code block
117
+ for side effects. Since there is no accessor, the code block is
118
+ executed immediately (i.e. no lazy evaluation).
119
+
120
+ The preconditions are run in order of definition. Nested contexts
121
+ will inherit the preconditions from the enclosing context, with out
122
+ preconditions running before inner preconditions.
123
+
124
+ #### Given examples:
125
+
126
+ <pre>
127
+ Given(:stack) { Stack.new }
128
+ </pre>
129
+
130
+ The given block is lazily run if 'stack' is ever referenced in the
131
+ test and the value of the block is bound to 'stack'. The first
132
+ reference to 'stack' in the specification will cause the code block to
133
+ execute. Futher references to 'stack' will reuse the previously
134
+ generated value.
135
+
136
+ <pre>
137
+ Given!(:original_size) { stack.size }
138
+ </pre>
139
+
140
+ The code block is run unconditionally once before each test and the
141
+ value of the block is bound to 'original_size'. This form is useful
142
+ when you want to record the value of something that might be affected
143
+ by the When code.
144
+
145
+ <pre>
146
+ Given { stack.clear }
147
+ </pre>
148
+
149
+ The given block is run unconditionally once before each test. This
150
+ form of given is used for code that is executed for side effects.
151
+
152
+ ### When
153
+
154
+ The _When_ block specifies the code to be tested ... oops, excuse me
155
+ ... specified. After the preconditions in the given section are met,
156
+ the when code block is run.
157
+
158
+ There should only be one _When_ block for a given context. However, a
159
+ _When_ in an outer context shoud be treated as a _Given_ in an inner
160
+ context. E.g.
161
+
162
+ <pre>
163
+ context "outer context" do
164
+ When { code specified in the outer context }
165
+ Then { assert something about the outer context }
166
+
167
+ context "inner context" do
168
+
169
+ # At this point, the _When_ of the outer context
170
+ # should be treated as a _Given_ of the inner context
171
+
172
+ When { code specified in the inner context }
173
+ Then { assert something about the inner context }
174
+ end
175
+ end
176
+ </pre>
177
+
178
+ #### When examples:
179
+
180
+ <pre>
181
+ When { stack.push(:item) }
182
+ </pre>
183
+
184
+ The code block is executed once per test. The effect of the _When{}_
185
+ block is very similar to _Given{}_. However, When is used to identify
186
+ the particular code that is being specified in the current context or
187
+ describe block.
188
+
189
+ <pre>
190
+ When(:result) { stack.pop }
191
+ </pre>
192
+
193
+ The code block is executed once per test and the value of the code
194
+ block is bound to 'result'. Use this form when the code under test
195
+ returns a value that you wish to interrogate in the _Then_ code.
196
+
197
+ If an exception occurs during the execution of the When block, the
198
+ exception is caught and a failure object is bound to 'result'. The
199
+ failure can be checked in a then block with the 'have_failed' matcher.
200
+
201
+ The failure object will rethrow the captured exception if anything
202
+ other than have_failed matcher is used on the failure object.
203
+
204
+ For example, if the stack is empty when it is popped, then it is
205
+ reasonable for pop to raise an UnderflowError. This is how you might
206
+ specify that behavior:
207
+
208
+ <pre>
209
+ When(:result) { stack.pop }
210
+ Then { result.should have_failed(UnderflowError, /empty/) }
211
+ </pre>
212
+
213
+ Note that the arguments to the 'have_failed' matcher are the same as
214
+ those given to the standard RSpec matcher 'raise_error'.
215
+
216
+ ### Then
217
+
218
+ The _Then_ clauses are the postconditions of the specification. These
219
+ then conditions must be true after the code under test (the _When_
220
+ clause) is run.
221
+
222
+ The code in the block of a _Then_ clause should be a single _should_
223
+ assertion. Code in _Then_ blocks should not have any side effects.
224
+
225
+ In RSpec terms, a _Then_ clause forms a RSpec Example that runs in the
226
+ context of an Example Group (defined by a describe or context clause).
227
+
228
+ Each Example Group must have at least one _Then_ clause, otherwise
229
+ there will be no examples to be run for that group. If all the
230
+ assertions in an example group are done via Invariants, then the group
231
+ should use an empty _Then_ clause, like this:
232
+
233
+ <pre>
234
+ Then { }
235
+ </pre>
236
+
237
+ #### Then examples:
238
+
239
+ <pre>
240
+ Then { stack.should be_empty }
241
+ </pre>
242
+
243
+ After the related _When_ block is run, the stack should be empty. If
244
+ it is not empty, the test will fail.
245
+
246
+ ### And
247
+
248
+ The _And_ clause is similar to _Then_, but do not form their own RSpec
249
+ examples. This means that _And_ clauses reuse the setup from the
250
+ _Then_ clause. Using a single _Then_ an multiple _And_ clauses in an
251
+ example group means the setup for that group is run only once (for the
252
+ _Then_ clause). This can be a significant speed savings where the
253
+ setup for an example group is expensive.
254
+
255
+ Some things to keep in mind about _And_ clauses:
256
+
257
+ 1. There must be at least one _Then_ in the example group and it must
258
+ be declared before the _And_ clauses. Forgetting the _Then_ clause
259
+ is an error.
260
+
261
+ 1. The code in the _And_ clause is run immediately after the first
262
+ _Then_ of an example group.
263
+
264
+ 1. And assertion failures in a _Then_ clause or a _And_ clause will
265
+ cause all the subsequent _And_ clauses to be skipped.
266
+
267
+ 1. Since _And_ clauses do not form their own RSpec examples, they are
268
+ not represented in the formatted output of RSpec. That means _And_
269
+ clauses do not produce dots in the Progress format, nor do they
270
+ appear in the documentation, html or textmate formats (options
271
+ -fhtml, -fdoc, or -ftextmate).
272
+
273
+ The choice to use an _And_ clause is primarily a speed consideration.
274
+ If an example group has expensive setup and there are a lot of _Then_
275
+ clauses, then choosing to make some of the _Then_ clauses into _And_
276
+ clause will speed up the spec. Otherwise it is probably better to
277
+ stick with _Then_ clauses.
278
+
279
+ #### Then/And examples:
280
+
281
+ <pre>
282
+ Then { pop_result.should == :top_item } # Required
283
+ And { stack.top.should == :second_item } # No Setup rerun
284
+ And { stack.depth.should == original_depth - 1 } # ... for these
285
+ </pre>
286
+
287
+ ### Invariant
288
+
289
+ The _Invariant_ block is a new idea that doesn't have an analog in
290
+ RSpec or Test::Unit. The invariant allows you specify things that
291
+ must always be true. In the stack example, <tt>empty?</tt> is defined
292
+ in term of <tt>size</tt>. Whenever <tt>size</tt> is 0,
293
+ <tt>empty?</tt> should be true. Whenever <tt>size</tt> is non-zero,
294
+ <tt>empty?</tt> should be false.
295
+
296
+ You can conceptually think of an _Invariant_ block as a _Then_ block
297
+ that automatically gets added to every _Then_ within its scope.
298
+
299
+ Invariants nested within a context only apply to the _Then_ blocks in
300
+ that context.
301
+
302
+ Invariants that reference a _Given_ precondition accessor must only be
303
+ used in contexts that define that accessor.
304
+
305
+ Notes:
306
+
307
+ 1. Since Invariants do not form their own RSpec example, they are not
308
+ represented in the RSpec formatted output (e.g. the '--format html'
309
+ option).
310
+
311
+ ## Configuration
312
+
313
+ Just require 'rspec/given' in the spec helper of your project and it
314
+ is ready to go.
315
+
316
+ If the RSpec format option document, html or textmate are chosen,
317
+ RSpec/Given will automatically add addition source code information to
318
+ the examples to produce better looking output. If you don't care about
319
+ the pretty output and wish to disable source code caching
320
+ unconditionally, then add the following line to your spec helper file:
321
+
322
+ <pre>
323
+ RSpec::Given.source_caching_disabled = true
324
+ </pre>
325
+
326
+ # Future Directions
327
+
328
+ I really like the way the Given framework is working out. I feel my
329
+ tests are much more like specifications when I use it. However, I'm
330
+ not entirely happy with it.
331
+
332
+ I would like to remove the need for the ".should" in all the
333
+ _Then_ blocks. In other words, instead of saying:
334
+
335
+ Then { x.should == y }
336
+
337
+ we could say:
338
+
339
+ Then { x == y }
340
+
341
+ I think the [wrong assertion library](http://rubygems.org/gems/wrong)
342
+ has laid some groundwork in this area.
343
+
344
+ # Links
345
+
346
+ * Github: [https://github.com/jimweirich/rspec-given](https://github.com/jimweirich/rspec-given)
347
+ * Clone URL: git://github.com/jimweirich/rspec-given.git
348
+ * Bug/Issue Reporting: [https://github.com/jimweirich/rspec-given/issues](https://github.com/jimweirich/rspec-given/issues)
349
+ * Continuous Integration: [http://travis-ci.org/#!/jimweirich/rspec-given](http://travis-ci.org/#!/jimweirich/rspec-given)
@@ -0,0 +1,48 @@
1
+ require 'rspec/given'
2
+ require 'spec_helper'
3
+
4
+ describe "And" do
5
+ Given(:info) { [] }
6
+ Given(:mock) { flexmock("mock") }
7
+
8
+ describe "And is called after Then" do
9
+ Given { mock.should_receive(:and_ran).once }
10
+ Then { info << "T" }
11
+ And {
12
+ info.should == ["T"]
13
+ mock.and_ran
14
+ }
15
+ end
16
+
17
+ describe "And is called only once with multiple Thens" do
18
+ Then { info << "T" }
19
+ Then { info << "T2" }
20
+ And { info.should == ["T"] }
21
+ end
22
+
23
+ describe "Inherited Ands are not run" do
24
+ Then { info << "T-OUTER" }
25
+ And { info << "A-OUTER" }
26
+ And { info.should == ["T-OUTER", "A-OUTER"] }
27
+
28
+ context "inner" do
29
+ Then { info << "T-INNER" }
30
+ And { info << "A-INNER" }
31
+ And { info.should == ["T-INNER", "A-INNER"] }
32
+ end
33
+ end
34
+
35
+ describe "Ands require a Then" do
36
+ begin
37
+ And { }
38
+ rescue StandardError => ex
39
+ @message = ex.message
40
+ end
41
+
42
+ it "should define a message" do
43
+ message = self.class.instance_eval { @message }
44
+ message.should =~ /and.*without.*then/i
45
+ end
46
+ end
47
+
48
+ end
@@ -20,7 +20,7 @@ describe Stack do
20
20
  When { stack.push(:an_item) }
21
21
 
22
22
  Then { stack.depth.should == 1 }
23
- Also { stack.top.should == :an_item }
23
+ Then { stack.top.should == :an_item }
24
24
  end
25
25
 
26
26
  context "when popping" do
@@ -36,7 +36,7 @@ describe Stack do
36
36
  When(:pop_result) { stack.pop }
37
37
 
38
38
  Then { pop_result.should == :an_item }
39
- Also { stack.depth.should == 0 }
39
+ Then { stack.depth.should == 0 }
40
40
  end
41
41
  end
42
42
 
data/lib/rspec/given.rb CHANGED
@@ -13,6 +13,8 @@ if RSpec::Given.using_old_rspec?
13
13
  require 'rspec/given/rspec1_given'
14
14
  else
15
15
  require 'rspec/given/version'
16
+ require 'rspec/given/module_methods'
17
+ require 'rspec/given/line_cache'
16
18
  require 'rspec/given/extensions'
17
19
  require 'rspec/given/configure'
18
20
  require 'rspec/given/failure'
@@ -1,9 +1,12 @@
1
1
  require 'rspec'
2
2
  require 'rspec/given/extensions'
3
3
  require 'rspec/given/have_failed'
4
+ require 'rspec/given/module_methods'
4
5
 
5
6
  RSpec.configure do |c|
6
7
  c.extend(RSpec::Given::ClassExtensions)
7
8
  c.include(RSpec::Given::InstanceExtensions)
8
9
  c.include(RSpec::Given::HaveFailed)
10
+
11
+ RSpec::Given.detect_formatters(c)
9
12
  end
@@ -1,4 +1,5 @@
1
1
  require 'rspec/given/failure'
2
+ require 'rspec/given/module_methods'
2
3
 
3
4
  module RSpec
4
5
  module Given
@@ -31,12 +32,12 @@ module RSpec
31
32
  end
32
33
  end
33
34
 
34
- def _rg_check_alsos # :nodoc:
35
- return if self.class._rg_context_info[:also_ran]
36
- self.class._rg_alsos.each do |block|
35
+ def _rg_check_ands # :nodoc:
36
+ return if self.class._rg_context_info[:and_ran]
37
+ self.class._rg_and_blocks.each do |block|
37
38
  instance_eval(&block)
38
39
  end
39
- self.class._rg_context_info[:also_ran] = true
40
+ self.class._rg_context_info[:and_ran] = true
40
41
  end
41
42
 
42
43
  # Implement the run-time semantics of the Then clause.
@@ -44,7 +45,7 @@ module RSpec
44
45
  _rg_establish_givens
45
46
  _rg_check_invariants
46
47
  instance_eval(&block)
47
- _rg_check_alsos
48
+ _rg_check_ands
48
49
  end
49
50
  end
50
51
 
@@ -62,14 +63,18 @@ module RSpec
62
63
  @_rg_invariants ||= []
63
64
  end
64
65
 
65
- def _rg_alsos
66
- @_rg_alsos ||= []
66
+ def _rg_and_blocks
67
+ @_rg_and_blocks ||= []
67
68
  end
68
69
 
69
70
  def _rg_context_info
70
71
  @_rg_contet_info ||= {}
71
72
  end
72
73
 
74
+ def _rg_cache
75
+ @_rg_cache ||= LineCache.new
76
+ end
77
+
73
78
  # Trigger the evaluation of a Given! block by referencing its
74
79
  # name.
75
80
  def _rg_trigger_given(name) # :nodoc:
@@ -161,7 +166,13 @@ module RSpec
161
166
  b = block.binding
162
167
  file = eval "__FILE__", b
163
168
  line = eval "__LINE__", b
164
- eval %{specify do _rg_then(&block) end}, binding, file, line
169
+ description = _rg_cache.line(file, line) unless RSpec::Given.source_caching_disabled
170
+ if description
171
+ cmd = "it(description)"
172
+ else
173
+ cmd = "specify"
174
+ end
175
+ eval %{#{cmd} do _rg_then(&block) end}, binding, file, line
165
176
  _rg_context_info[:then_defined] = true
166
177
  end
167
178
 
@@ -171,9 +182,9 @@ module RSpec
171
182
  _rg_invariants << block
172
183
  end
173
184
 
174
- def Also(&block)
175
- fail "Also defined without a Then" unless _rg_context_info[:then_defined]
176
- _rg_alsos << block
185
+ def And(&block)
186
+ fail "And defined without a Then" unless _rg_context_info[:then_defined]
187
+ _rg_and_blocks << block
177
188
  end
178
189
  end
179
190
  end
@@ -0,0 +1,34 @@
1
+ module RSpec
2
+ module Given
3
+ class LineCache
4
+ def initialize
5
+ @lines = {}
6
+ end
7
+
8
+ def line(file_name, line)
9
+ lines = get_lines(file_name)
10
+ extract_lines_from(lines, line-1)
11
+ end
12
+
13
+ private
14
+
15
+ def extract_lines_from(lines, index)
16
+ result = lines[index]
17
+ if result =~ /\{ *$/
18
+ result =~ /^( *)[^ ]/
19
+ leading_spaces = $1
20
+ indent = leading_spaces.size
21
+ begin
22
+ index += 1
23
+ result << lines[index]
24
+ end while lines[index] =~ /^#{leading_spaces} /
25
+ end
26
+ result
27
+ end
28
+
29
+ def get_lines(file_name)
30
+ @lines[file_name] ||= open(file_name) { |f| f.readlines }
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,16 @@
1
+ module RSpec
2
+ module Given
3
+ def self.source_caching_disabled
4
+ @_rg_source_caching_disabled
5
+ end
6
+
7
+ def self.source_caching_disabled=(value)
8
+ @_rg_source_caching_disabled = value
9
+ end
10
+
11
+ def self.detect_formatters(c)
12
+ format_active = c.formatters.any? { |f| f.class.name !~ /ProgressFormatter/ }
13
+ RSpec::Given.source_caching_disabled = ! format_active
14
+ end
15
+ end
16
+ end
@@ -5,7 +5,7 @@ module RSpec
5
5
  VERSION_MINOR = 1,
6
6
  VERSION_BUILD = 0,
7
7
  VERSION_BETA = 'beta',
8
- VERSION_BETANUM = '1'
8
+ VERSION_BETANUM = '4'
9
9
  ]
10
10
  VERSION = VERSION_NUMBERS.join(".")
11
11
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rspec-given
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.1.0.beta.1
4
+ version: 2.1.0.beta.4
5
5
  prerelease: 6
6
6
  platform: ruby
7
7
  authors:
@@ -9,11 +9,11 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-09-12 00:00:00.000000000 Z
12
+ date: 2012-09-13 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rspec
16
- requirement: &70227316783380 !ruby/object:Gem::Requirement
16
+ requirement: &70145913512260 !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
19
19
  - - ! '>'
@@ -21,10 +21,10 @@ dependencies:
21
21
  version: 1.2.8
22
22
  type: :runtime
23
23
  prerelease: false
24
- version_requirements: *70227316783380
24
+ version_requirements: *70145913512260
25
25
  - !ruby/object:Gem::Dependency
26
26
  name: bluecloth
27
- requirement: &70227316782580 !ruby/object:Gem::Requirement
27
+ requirement: &70145913511800 !ruby/object:Gem::Requirement
28
28
  none: false
29
29
  requirements:
30
30
  - - ! '>='
@@ -32,10 +32,10 @@ dependencies:
32
32
  version: '0'
33
33
  type: :development
34
34
  prerelease: false
35
- version_requirements: *70227316782580
35
+ version_requirements: *70145913511800
36
36
  - !ruby/object:Gem::Dependency
37
37
  name: rdoc
38
- requirement: &70227316781360 !ruby/object:Gem::Requirement
38
+ requirement: &70145913511100 !ruby/object:Gem::Requirement
39
39
  none: false
40
40
  requirements:
41
41
  - - ! '>'
@@ -43,7 +43,7 @@ dependencies:
43
43
  version: 2.4.2
44
44
  type: :development
45
45
  prerelease: false
46
- version_requirements: *70227316781360
46
+ version_requirements: *70145913511100
47
47
  description: ! 'Given is an RSpec extension that allows explicit definition of the
48
48
 
49
49
  pre and post-conditions for code under test.
@@ -58,16 +58,20 @@ files:
58
58
  - Gemfile.lock
59
59
  - MIT-LICENSE
60
60
  - Rakefile
61
+ - README
61
62
  - README.md
63
+ - README.old
62
64
  - lib/rspec-given.rb
63
65
  - lib/rspec/given/configure.rb
64
66
  - lib/rspec/given/extensions.rb
65
67
  - lib/rspec/given/failure.rb
66
68
  - lib/rspec/given/have_failed.rb
69
+ - lib/rspec/given/line_cache.rb
70
+ - lib/rspec/given/module_methods.rb
67
71
  - lib/rspec/given/rspec1_given.rb
68
72
  - lib/rspec/given/version.rb
69
73
  - lib/rspec/given.rb
70
- - examples/integration/also_spec.rb
74
+ - examples/integration/and_spec.rb
71
75
  - examples/integration/focused_line_spec.rb
72
76
  - examples/integration/given_spec.rb
73
77
  - examples/integration/invariant_spec.rb
@@ -1,48 +0,0 @@
1
- require 'rspec/given'
2
- require 'spec_helper'
3
-
4
- describe "Also" do
5
- Given(:info) { [] }
6
- Given(:mock) { flexmock("mock") }
7
-
8
- describe "Also is called after Then" do
9
- Given { mock.should_receive(:also_ran).once }
10
- Then { info << "T" }
11
- Also {
12
- info.should == ["T"]
13
- mock.also_ran
14
- }
15
- end
16
-
17
- describe "Also is called only once with multiple Thens" do
18
- Then { info << "T" }
19
- Then { info << "T2" }
20
- Also { info.should == ["T"] }
21
- end
22
-
23
- describe "Inherited Alsos are not run" do
24
- Then { info << "T-OUTER" }
25
- Also { info << "A-OUTER" }
26
- Also { info.should == ["T-OUTER", "A-OUTER"] }
27
-
28
- context "inner" do
29
- Then { info << "T-INNER" }
30
- Also { info << "A-INNER" }
31
- Also { info.should == ["T-INNER", "A-INNER"] }
32
- end
33
- end
34
-
35
- describe "Alsos require a Then" do
36
- begin
37
- Also { }
38
- rescue StandardError => ex
39
- @message = ex.message
40
- end
41
-
42
- it "should define a message" do
43
- message = self.class.instance_eval { @message }
44
- message.should =~ /also.*without.*then/i
45
- end
46
- end
47
-
48
- end