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

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/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