rspec 0.5.3 → 0.5.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (100) hide show
  1. data/CHANGES +57 -32
  2. data/EXAMPLES.rd +0 -0
  3. data/Rakefile +22 -21
  4. data/bin/spec +9 -11
  5. data/doc/README +1 -3
  6. data/doc/plugin/syntax.rb +27 -5
  7. data/doc/src/core_team.page +22 -0
  8. data/doc/src/default.css +11 -11
  9. data/doc/src/default.template +0 -1
  10. data/doc/src/documentation/index.page +183 -8
  11. data/doc/src/documentation/meta.info +7 -7
  12. data/doc/src/documentation/mocks.page +168 -109
  13. data/doc/src/documentation/underscores.page +20 -0
  14. data/doc/src/examples.page +2 -1
  15. data/doc/src/images/David_and_Aslak.jpg +0 -0
  16. data/doc/src/images/Whats_That_Dude.jpg +0 -0
  17. data/doc/src/index.page +70 -3
  18. data/doc/src/meta.info +18 -11
  19. data/doc/src/tools/index.page +40 -134
  20. data/doc/src/tools/meta.info +9 -3
  21. data/doc/src/tools/rails.page +3 -1
  22. data/doc/src/tools/rake.page +20 -3
  23. data/doc/src/tools/rcov.page +19 -0
  24. data/doc/src/tools/spec.page +99 -0
  25. data/doc/src/tools/test2rspec.page +2 -4
  26. data/doc/src/tutorials/index.page +52 -0
  27. data/doc/src/tutorials/meta.info +31 -0
  28. data/doc/src/tutorials/notes.txt +252 -0
  29. data/doc/src/tutorials/stack.rb +11 -0
  30. data/doc/src/tutorials/stack_01.page +224 -0
  31. data/doc/src/tutorials/stack_02.page +180 -0
  32. data/doc/src/tutorials/stack_03.page +291 -0
  33. data/doc/src/tutorials/stack_04.page +203 -0
  34. data/doc/src/tutorials/stack_04.page.orig +123 -0
  35. data/doc/src/tutorials/stack_05.page +90 -0
  36. data/doc/src/tutorials/stack_05.page.orig +124 -0
  37. data/doc/src/tutorials/stack_06.page +359 -0
  38. data/doc/src/tutorials/stack_06.page.orig +359 -0
  39. data/doc/src/tutorials/stack_spec.rb +41 -0
  40. data/examples/airport_spec.rb +4 -4
  41. data/examples/{spec_framework_spec.rb → bdd_framework_spec.rb} +6 -7
  42. data/examples/mocking_spec.rb +0 -5
  43. data/examples/stack_spec.rb +6 -7
  44. data/examples/sugar_spec.rb +14 -0
  45. data/lib/spec/api.rb +5 -2
  46. data/lib/spec/api/helper/should_base.rb +17 -22
  47. data/lib/spec/api/helper/should_helper.rb +4 -3
  48. data/lib/spec/api/helper/should_negator.rb +3 -2
  49. data/lib/spec/api/mocks/argument_expectation.rb +104 -0
  50. data/lib/spec/api/{mock.rb → mocks/message_expectation.rb} +47 -96
  51. data/lib/spec/api/mocks/mock.rb +63 -0
  52. data/lib/spec/api/mocks/order_group.rb +21 -0
  53. data/lib/spec/api/sugar.rb +47 -0
  54. data/lib/spec/rake/rcov_verify.rb +45 -0
  55. data/lib/spec/rake/spectask.rb +41 -56
  56. data/lib/spec/runner.rb +4 -1
  57. data/lib/spec/runner/backtrace_tweaker.rb +24 -3
  58. data/lib/spec/runner/base_text_formatter.rb +28 -0
  59. data/lib/spec/runner/context.rb +21 -18
  60. data/lib/spec/runner/context_runner.rb +20 -31
  61. data/lib/spec/runner/execution_context.rb +3 -3
  62. data/lib/spec/runner/kernel_ext.rb +10 -1
  63. data/lib/spec/runner/option_parser.rb +32 -14
  64. data/lib/spec/runner/progress_bar_formatter.rb +21 -0
  65. data/lib/spec/runner/rdoc_formatter.rb +15 -5
  66. data/lib/spec/runner/reporter.rb +100 -0
  67. data/lib/spec/runner/specdoc_formatter.rb +20 -0
  68. data/lib/spec/runner/specification.rb +42 -22
  69. data/lib/spec/version.rb +1 -1
  70. data/test/rcov/rcov_testtask.rb +1 -0
  71. data/test/spec/api/duck_type_test.rb +4 -4
  72. data/test/spec/api/helper/raising_test.rb +37 -17
  73. data/test/spec/api/{mock_arg_constraints_test.rb → mocks/mock_arg_constraints_test.rb} +10 -4
  74. data/test/spec/api/mocks/mock_ordering_test.rb +62 -0
  75. data/test/spec/api/{mock_test.rb → mocks/mock_test.rb} +30 -7
  76. data/test/spec/api/mocks/null_object_test.rb +31 -0
  77. data/test/spec/api/sugar_test.rb +71 -0
  78. data/test/spec/runner/backtrace_tweaker_test.rb +52 -4
  79. data/test/spec/runner/context_runner_test.rb +41 -21
  80. data/test/spec/runner/context_test.rb +60 -32
  81. data/test/spec/runner/execution_context_test.rb +4 -3
  82. data/test/spec/runner/failure_dump_test.rb +92 -0
  83. data/test/spec/runner/kernel_ext_test.rb +1 -2
  84. data/test/spec/runner/option_parser_test.rb +48 -28
  85. data/test/spec/runner/progress_bar_formatter_test.rb +48 -0
  86. data/test/spec/runner/rdoc_formatter_test.rb +31 -4
  87. data/test/spec/runner/reporter_test.rb +103 -0
  88. data/test/spec/runner/specdoc_formatter_test.rb +50 -0
  89. data/test/spec/runner/specification_test.rb +49 -11
  90. data/test/test_helper.rb +1 -4
  91. metadata +46 -15
  92. data/doc/src/community.page +0 -7
  93. data/doc/src/documentation/api.page +0 -185
  94. data/doc/src/why_rspec.page +0 -7
  95. data/examples/empty_stack_spec.rb +0 -22
  96. data/examples/team_spec.rb +0 -30
  97. data/lib/spec/api/duck_type.rb +0 -16
  98. data/lib/spec/runner/simple_text_reporter.rb +0 -88
  99. data/test/rcov/rcov_verify.rb +0 -28
  100. data/test/spec/runner/simple_text_reporter_test.rb +0 -123
@@ -0,0 +1,180 @@
1
+ h2. A Simple Stack
2
+
3
+ h3. An Empty Stack
4
+
5
+ So now we know that when you first create a stack it is empty. What's next? We could make some more specifications about a new stack, but the fact that it is an empty stack is more interesting from a behavioural perspective than a new stack. So let's start talking about the behaviour of an <em>empty</em> stack.
6
+
7
+ We all know the standard messages we want on a stack: some variation of push, pop and top. What should happen when we send 'push' to an empty stack? The usual first move is to specify that it has a size of 1, but we don't have a <code>size</code> method, nor do we want one if we can avoid it. We can, however, specify that it is no longer empty after a push.
8
+
9
+ <ruby>
10
+ context "An empty stack" do
11
+ specify "should not be empty after 'push'" do
12
+ end
13
+ end
14
+ </ruby>
15
+ <br>
16
+ <pre>
17
+ $ spec stack_spec.rb -f s
18
+
19
+ A new stack
20
+ - should be empty
21
+
22
+ An empty stack
23
+ - should not be empty after 'push'
24
+
25
+ Finished in 0.000391 seconds
26
+
27
+ 2 contexts, 2 specifications, 0 failures
28
+ </pre>
29
+
30
+ See how that's reading like a specification document? OK, now let's fill in the specification. First we add the setup for our context.
31
+
32
+ <ruby>
33
+ context "An empty stack" do
34
+ setup do
35
+ @stack = Stack.new
36
+ end
37
+ specify "should not be empty after 'push'" do
38
+ end
39
+ end
40
+ </ruby>
41
+ <br>
42
+ <pre>
43
+ $ spec stack_spec.rb -f s
44
+
45
+ A new stack
46
+ - should be empty
47
+
48
+ An empty stack
49
+ - should not be empty after 'push'
50
+
51
+ Finished in 0.000444 seconds
52
+
53
+ 2 contexts, 2 specifications, 0 failures
54
+ </pre>
55
+
56
+ No change in the result. Now we'll push something on to the stack.
57
+
58
+ <ruby>
59
+ context "An empty stack" do
60
+ setup do
61
+ @stack = Stack.new
62
+ end
63
+ specify "should not be empty after 'push'" do
64
+ @stack.push 37
65
+ end
66
+ end
67
+ </ruby>
68
+ <br>
69
+ <pre>
70
+ $ spec stack_spec.rb -f s
71
+
72
+ A new stack
73
+ - should be empty
74
+
75
+ An empty stack
76
+ - should not be empty after 'push' (FAILED - 1)
77
+
78
+ 1)
79
+ NoMethodError in 'An empty stack should not be empty after 'push''
80
+ undefined method `push' for #<Stack:0x36d0e0>
81
+ ./stack_spec.rb:17:in `should not be empty after 'push''
82
+
83
+ Finished in 0.000548 seconds
84
+
85
+ 2 contexts, 2 specifications, 1 failure
86
+ </pre>
87
+
88
+ The <code>NoMethodError</code> tells us we need to add a push method to the stack.
89
+
90
+ <ruby>
91
+ class Stack
92
+ def empty?
93
+ true
94
+ end
95
+ def push item
96
+ end
97
+ end
98
+ </ruby>
99
+ <br>
100
+ <pre>
101
+ $ spec stack_spec.rb -f s
102
+
103
+ A new stack
104
+ - should be empty
105
+
106
+ An empty stack
107
+ - should not be empty after 'push'
108
+
109
+ Finished in 0.000427 seconds
110
+
111
+ 2 contexts, 2 specifications, 0 failures
112
+ </pre>
113
+
114
+ Remember, add a little bit at a time, run the specs and resolve name errors (these are like compilation failures in java and C#). Next we set our expectation:
115
+
116
+ <ruby>
117
+ context "An empty stack" do
118
+ setup do
119
+ @stack = Stack.new
120
+ end
121
+ specify "should not be empty after 'push'" do
122
+ @stack.push 37
123
+ @stack.should_not_be_empty
124
+ end
125
+ end
126
+ </ruby>
127
+ <br>
128
+ <pre>
129
+ $ spec stack_spec.rb -f s
130
+
131
+ A new stack
132
+ - should be empty
133
+
134
+ An empty stack
135
+ - should not be empty after 'push' (FAILED - 1)
136
+
137
+ 1)
138
+ ExpectationNotMetError in 'An empty stack should not be empty after 'push''
139
+ Stack #<Stack:0x36cf50> should not be empty
140
+ ./stack_spec.rb:18:in `should not be empty after 'push''
141
+
142
+ Finished in 0.000604 seconds
143
+
144
+ 2 contexts, 2 specifications, 1 failure
145
+ </pre>
146
+
147
+ The <code>ExpectationNotMetError</code> tells us we have something to implement. We want to do the simplest thing that we can do to meet our existing expectations. At this point we don't know anything about collections or even specific values, so we can just manage whether or not it is empty.
148
+
149
+ <ruby>
150
+ class Stack
151
+ def initialize
152
+ @empty = true
153
+ end
154
+ def empty?
155
+ @empty
156
+ end
157
+ def push item
158
+ @empty = false
159
+ end
160
+ end
161
+ </ruby>
162
+ <br>
163
+ <pre>
164
+ $ spec stack_spec.rb -f s
165
+
166
+ A new stack
167
+ - should be empty
168
+
169
+ An empty stack
170
+ - should not be empty after 'push'
171
+
172
+ Finished in 0.000443 seconds
173
+
174
+ 2 contexts, 2 specifications, 0 failures
175
+ </pre>
176
+
177
+ Again, this may seem a little odd, but we haven't specified anything yet about what happens to things that get pushed on to the stack. That's right around the corner though...
178
+
179
+ <a href="stack_01.html">Previous</a> |
180
+ <a href="stack_03.html">Next</a>
@@ -0,0 +1,291 @@
1
+ h2. A Simple Stack - eliminating duplication
2
+
3
+ h3. What to specify next?
4
+
5
+ Picking the next thing to specify is always a challenge (just as picking the next thing to test is in TDD). Ideally, you want to specify the simplest thing that you can imagine implementing. Of course, thinking about implementation seems to fly in the face of a core tenet of TDD and BDD: focus on interface - focus on behaviour. So you have a couple of opposing forces and notions guiding this decision. The bottom line is that it's not that important which one you pick next. The important thing is that as soon as you recognize that you've headed down the wrong path (one which requires a lot of implementation to meet the newest specification), roll back immediately and pick a different "next step".
6
+
7
+ For our problem, there seem to be (at least) two logical potential next steps. We know that pushing on to an empty stack results in the stack no longer being empty. So one logical next step might be to specify how an empty stack behaves when sending it a different message. Another might be to send push to a non-empty stack. But what I'd really like to know is what happened to the object we just pushed!
8
+
9
+ To specify that, we have to move diagonally a bit. We need to specify the stack's response to a new message starting in a new state - a new context. We're going to start with a stack with one item already pushed onto it and specify what happens when you send it 'top'. Why top and not pop? In this case, top is simpler than pop - top just returns the top object, while pop also removes it from the stack.
10
+
11
+ h3. Send top to a stack with one item
12
+
13
+ Start by adding a new context in stack_spec.rb. Remember, the context is an object (or set of objects) in a known state, so we'll go ahead and add the setup right away
14
+
15
+ <ruby>
16
+ context "A stack with one item" do
17
+ specify "should return top when you send it 'top'" do
18
+ end
19
+ end
20
+ </ruby>
21
+ <br>
22
+ <pre>
23
+ $ spec stack_spec.rb -f s
24
+
25
+ A new stack
26
+ - should be empty
27
+
28
+ An empty stack
29
+ - should keep its mouth shut when you send it 'push'
30
+ - should not be empty after 'push'
31
+
32
+ A stack with one item
33
+ - should return top when you send it 'top'
34
+
35
+ Finished in 0.000693 seconds
36
+
37
+ 3 contexts, 4 specifications, 0 failures
38
+ </pre>
39
+
40
+ Add the setup...
41
+
42
+ <ruby>
43
+ context "A stack with one item" do
44
+ setup do
45
+ @stack = Stack.new
46
+ @stack.push "one item"
47
+ end
48
+
49
+ specify "should return top when you send it 'top'" do
50
+ end
51
+ end
52
+ </ruby>
53
+ <br>
54
+ <pre>
55
+ $ spec stack_spec.rb -f s
56
+
57
+ A new stack
58
+ - should be empty
59
+
60
+ An empty stack
61
+ - should keep its mouth shut when you send it 'push'
62
+ - should not be empty after 'push'
63
+
64
+ A stack with one item
65
+ - should return top when you send it 'top'
66
+
67
+ Finished in 0.000733 seconds
68
+
69
+ 3 contexts, 4 specifications, 0 failures
70
+ </pre>
71
+
72
+ No change in the output. Add the expectation...
73
+
74
+ <ruby>
75
+ context "A stack with one item" do
76
+ setup do
77
+ @stack = Stack.new
78
+ @stack.push "one item"
79
+ end
80
+
81
+ specify "should return top when you send it 'top'" do
82
+ @stack.top.should_equal "one item"
83
+ end
84
+ end
85
+ </ruby>
86
+ <br>
87
+ <pre>
88
+ $ spec stack_spec.rb -f s
89
+
90
+ A new stack
91
+ - should be empty
92
+
93
+ An empty stack
94
+ - should keep its mouth shut when you send it 'push'
95
+ - should not be empty after 'push'
96
+
97
+ A stack with one item
98
+ - should return top when you send it 'top' (FAILED - 1)
99
+
100
+ 1)
101
+ NoMethodError in 'A stack with one item should return top when you send it 'top''
102
+ undefined method `top' for #<Stack:0x36bd44 @empty=false>
103
+ ./stack_spec.rb:35:in `should return top when you send it 'top''
104
+
105
+ Finished in 0.000863 seconds
106
+
107
+ 3 contexts, 4 specifications, 1 failure
108
+ </pre>
109
+
110
+ The <code>NoMethodError</code> tells us to add the 'top' method.
111
+
112
+ <ruby>
113
+ class Stack
114
+ ...
115
+ def top
116
+ end
117
+ end
118
+ </ruby>
119
+ <br>
120
+ <pre>
121
+ $ spec stack_spec.rb -f s
122
+
123
+ A new stack
124
+ - should be empty
125
+
126
+ An empty stack
127
+ - should keep its mouth shut when you send it 'push'
128
+ - should not be empty after 'push'
129
+
130
+ A stack with one item
131
+ - should return top when you send it 'top' (FAILED - 1)
132
+
133
+ 1)
134
+ ExpectationNotMetError in 'A stack with one item should return top when you send it 'top''
135
+ nil should equal "one item"
136
+ ./stack_spec.rb:35:in `should return top when you send it 'top''
137
+
138
+ Finished in 0.000867 seconds
139
+
140
+ 3 contexts, 4 specifications, 1 failure
141
+ </pre>
142
+
143
+ The <code>ExpectationNotMetError</code> tells us to implement something. What's the simplest thing we can add to meet all of the current expectations?
144
+
145
+ <ruby>
146
+ class Stack
147
+ ...
148
+ def top
149
+ "one item"
150
+ end
151
+ end
152
+ </ruby>
153
+ <br>
154
+ <pre>
155
+ $ spec stack_spec.rb -f s
156
+
157
+ A new stack
158
+ - should be empty
159
+
160
+ An empty stack
161
+ - should keep its mouth shut when you send it 'push'
162
+ - should not be empty after 'push'
163
+
164
+ A stack with one item
165
+ - should return top when you send it 'top'
166
+
167
+ Finished in 0.000744 seconds
168
+
169
+ 3 contexts, 4 specifications, 0 failures
170
+ </pre>
171
+
172
+ So now we've hard coded something even more obviously wrong than before. True/false/empty, etc - that was all a bit more subtle. This case is much more obvious. There are a couple of ways to view the problem. One is that we've got this hard coded value. The bigger problem is that we now have duplication between the specs and the code. We want to get rid of it. How do you eliminate duplication? Refactor! And since we have a suite (albeit small) of passing specifications, we can now refactor safely.
173
+
174
+ If you're not familiar with refactoring, check out <a href="http://www.refactoring.com/">http://www.refactoring.com/</a>. We'll do some now, but we won't be examining the steps too deeply. The basic idea is that we want to change structure/implementation without affecting behaviour. Running the specs and watching them pass between each step proves that the behaviour is in tact.
175
+
176
+ First, we keep track of the item we add...
177
+
178
+ <ruby>
179
+ class Stack
180
+ def initialize
181
+ @empty = true
182
+ end
183
+ def empty?
184
+ @empty
185
+ end
186
+ def push item
187
+ @empty = false
188
+ @item = item
189
+ end
190
+ def top
191
+ @item
192
+ end
193
+ end
194
+ </ruby>
195
+ <br>
196
+ <pre>
197
+ $ spec stack_spec.rb -f s
198
+
199
+ A new stack
200
+ - should be empty
201
+
202
+ An empty stack
203
+ - should keep its mouth shut when you send it 'push'
204
+ - should not be empty after 'push'
205
+
206
+ A stack with one item
207
+ - should return top when you send it 'top'
208
+
209
+ Finished in 0.000846 seconds
210
+
211
+ 3 contexts, 4 specifications, 0 failures
212
+ </pre>
213
+
214
+ Now let's use that to determine "emptiness"...
215
+
216
+ <ruby>
217
+ class Stack
218
+ def initialize
219
+ @empty = true
220
+ end
221
+ def empty?
222
+ @item.nil?
223
+ end
224
+ def push item
225
+ @empty = false
226
+ @item = item
227
+ end
228
+ def top
229
+ @item
230
+ end
231
+ end
232
+ </ruby>
233
+ <br>
234
+ <pre>
235
+ $ spec stack_spec.rb -f s
236
+
237
+ A new stack
238
+ - should be empty
239
+
240
+ An empty stack
241
+ - should keep its mouth shut when you send it 'push'
242
+ - should not be empty after 'push'
243
+
244
+ A stack with one item
245
+ - should return top when you send it 'top'
246
+
247
+ Finished in 0.000764 seconds
248
+
249
+ 3 contexts, 4 specifications, 0 failures
250
+ </pre>
251
+
252
+ Now we can eliminate <code>@empty</code> (which means we can eliminate <code>initialize</code> as well).
253
+
254
+ <ruby>
255
+ class Stack
256
+ def empty?
257
+ @item.nil?
258
+ end
259
+ def push item
260
+ @item = item
261
+ end
262
+ def top
263
+ @item
264
+ end
265
+ end
266
+ </ruby>
267
+ <br>
268
+ <pre>
269
+ $ spec stack_spec.rb -f s
270
+
271
+ A new stack
272
+ - should be empty
273
+
274
+ An empty stack
275
+ - should keep its mouth shut when you send it 'push'
276
+ - should not be empty after 'push'
277
+
278
+ A stack with one item
279
+ - should return top when you send it 'top'
280
+
281
+ Finished in 0.000737 seconds
282
+
283
+ 3 contexts, 4 specifications, 0 failures
284
+ </pre>
285
+
286
+ You may wonder why we chose to refactor at this point, but we didn't the first time we had duplication between the tests and code. Remember the first step we took? It was to return <code>true</code> for <code>empty?</code>. Though more subtle than "one item", that was duplication between the specs and the code. The problem was that we didn't have any other methods on the stack that we could use. We would have had to contrive implementation that we had no specification for. At this point, however, we were able to make use of data we were passing into the the stack from the specification, so we were in a position to change things without adding things we hadn't specified yet.
287
+
288
+ To be continued...
289
+
290
+ <a href="stack_02.html">Previous</a> |
291
+ <a href="stack_04.html">Next</a>