rspec 0.5.4 → 0.5.5
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGES +10 -2
- data/EXAMPLES.rd +34 -0
- data/README +1 -1
- data/Rakefile +23 -28
- data/bin/spec +0 -1
- data/doc/src/core_team.page +18 -9
- data/doc/src/tools/rails.page +71 -5
- data/doc/src/tools/rake.page +5 -8
- data/doc/src/tools/rcov.page +14 -5
- data/doc/src/tools/spec.page +33 -18
- data/doc/src/tutorials/meta.info +6 -1
- data/doc/src/tutorials/stack.rb +1 -1
- data/doc/src/tutorials/stack_01.page +2 -0
- data/doc/src/tutorials/stack_02.page +6 -4
- data/doc/src/tutorials/stack_03.page +7 -15
- data/doc/src/tutorials/stack_04.page +39 -78
- data/doc/src/tutorials/stack_05.page +1 -1
- data/doc/src/tutorials/stack_spec.rb +2 -18
- data/lib/spec/rake/rcov_verify.rb +2 -2
- data/lib/spec/rake/spectask.rb +4 -9
- data/lib/spec/runner.rb +1 -0
- data/lib/spec/runner/backtrace_tweaker.rb +2 -0
- data/lib/spec/runner/context.rb +7 -5
- data/lib/spec/runner/context_runner.rb +4 -4
- data/lib/spec/runner/kernel_ext.rb +1 -1
- data/lib/spec/runner/spec_matcher.rb +39 -0
- data/lib/spec/runner/specification.rb +3 -3
- data/lib/spec/version.rb +1 -1
- data/test/spec/api/helper/equality_test.rb +1 -1
- data/test/spec/runner/backtrace_tweaker_test.rb +15 -9
- data/test/spec/runner/context_matching_test.rb +35 -0
- data/test/spec/runner/context_runner_test.rb +16 -16
- data/test/spec/runner/context_test.rb +0 -21
- data/test/spec/runner/spec_matcher_test.rb +42 -0
- data/test/spec/runner/specification_test.rb +9 -4
- metadata +12 -10
- data/doc/reference/rspec reference.page +0 -0
- data/test/rcov/rcov_testtask.rb +0 -46
@@ -220,5 +220,7 @@ Finished in 0.000256 seconds
|
|
220
220
|
|
221
221
|
And thus we have completed our first specification: "A new stack should be empty"
|
222
222
|
|
223
|
+
If you've never had any experience, returning <code>true</code> from <code>empty?</code> may seem a bit strange. Even if you have, you may not feel that the cycle is complete yet. "Test-Code-Refactor", right? Or rather "Spec-Code-Refactor". At this point, we should refactor to eliminate duplication, and you might argue that there is duplication between the spec expecting true and the method returning true. The problem right now is that we have no specs with expectations of the stack being anything other than empty. Any conditional logic we might implement here would be adding new behaviour. Refactoring is defined as changing structure without changing behaviour. And so, as much as we'd like to change <code>true</code> to something more useful, we need to take that urge and recognize that, in this case, we have a deficiency in our specifications - not in the code.
|
224
|
+
|
223
225
|
<a href="stack_02.html">Next</a>
|
224
226
|
|
@@ -1,10 +1,10 @@
|
|
1
1
|
h2. A Simple Stack
|
2
2
|
|
3
|
-
h3.
|
3
|
+
h3. Choosing the next Specification
|
4
4
|
|
5
|
-
|
5
|
+
We left our code in a state in which it could not be refactored because adding conditional logic would be adding new behaviour at this point (which is not refactoring). We wanted to refactor because we had a hard-coded return value from a method that is begging for some conditional logic. So let's choose a specification to focus on next that will help us to address that. We want a specification that will result in a non-empty stack.
|
6
6
|
|
7
|
-
|
7
|
+
Since an "empty stack" seems more interesting from a behavioural perspective than a "new stack", let's start talking about the behaviour of an <em>empty</em> stack.
|
8
8
|
|
9
9
|
<ruby>
|
10
10
|
context "An empty stack" do
|
@@ -111,7 +111,9 @@ Finished in 0.000427 seconds
|
|
111
111
|
2 contexts, 2 specifications, 0 failures
|
112
112
|
</pre>
|
113
113
|
|
114
|
-
|
114
|
+
The idea is to add a little bit of spec, just enough to get some kind of failure, then just enough code to get the code to meet the expectations expressed in the spec. In this case, the NameError was like a compilation failure in java or C#.
|
115
|
+
|
116
|
+
Next we set our expectation:
|
115
117
|
|
116
118
|
<ruby>
|
117
119
|
context "An empty stack" do
|
@@ -4,13 +4,13 @@ h3. What to specify next?
|
|
4
4
|
|
5
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
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
|
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 item we just pushed onto the stack!
|
8
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
|
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 item, while pop also removes it from the stack.
|
10
10
|
|
11
11
|
h3. Send top to a stack with one item
|
12
12
|
|
13
|
-
Start by adding a new context in stack_spec.rb.
|
13
|
+
Start by adding a new context and spec in stack_spec.rb.
|
14
14
|
|
15
15
|
<ruby>
|
16
16
|
context "A stack with one item" do
|
@@ -26,7 +26,6 @@ A new stack
|
|
26
26
|
- should be empty
|
27
27
|
|
28
28
|
An empty stack
|
29
|
-
- should keep its mouth shut when you send it 'push'
|
30
29
|
- should not be empty after 'push'
|
31
30
|
|
32
31
|
A stack with one item
|
@@ -58,7 +57,6 @@ A new stack
|
|
58
57
|
- should be empty
|
59
58
|
|
60
59
|
An empty stack
|
61
|
-
- should keep its mouth shut when you send it 'push'
|
62
60
|
- should not be empty after 'push'
|
63
61
|
|
64
62
|
A stack with one item
|
@@ -91,7 +89,6 @@ A new stack
|
|
91
89
|
- should be empty
|
92
90
|
|
93
91
|
An empty stack
|
94
|
-
- should keep its mouth shut when you send it 'push'
|
95
92
|
- should not be empty after 'push'
|
96
93
|
|
97
94
|
A stack with one item
|
@@ -124,7 +121,6 @@ A new stack
|
|
124
121
|
- should be empty
|
125
122
|
|
126
123
|
An empty stack
|
127
|
-
- should keep its mouth shut when you send it 'push'
|
128
124
|
- should not be empty after 'push'
|
129
125
|
|
130
126
|
A stack with one item
|
@@ -158,7 +154,6 @@ A new stack
|
|
158
154
|
- should be empty
|
159
155
|
|
160
156
|
An empty stack
|
161
|
-
- should keep its mouth shut when you send it 'push'
|
162
157
|
- should not be empty after 'push'
|
163
158
|
|
164
159
|
A stack with one item
|
@@ -169,11 +164,11 @@ Finished in 0.000744 seconds
|
|
169
164
|
3 contexts, 4 specifications, 0 failures
|
170
165
|
</pre>
|
171
166
|
|
172
|
-
|
167
|
+
Again we have duplication between the specs and the code ("one item") and we want to get rid of it. This time, however, we have enough specs and entry points that there is actually something to refactor to.
|
173
168
|
|
174
169
|
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
170
|
|
176
|
-
First, we
|
171
|
+
First, we save the item we add and return that from <code>top</code> ...
|
177
172
|
|
178
173
|
<ruby>
|
179
174
|
class Stack
|
@@ -200,7 +195,6 @@ A new stack
|
|
200
195
|
- should be empty
|
201
196
|
|
202
197
|
An empty stack
|
203
|
-
- should keep its mouth shut when you send it 'push'
|
204
198
|
- should not be empty after 'push'
|
205
199
|
|
206
200
|
A stack with one item
|
@@ -211,7 +205,7 @@ Finished in 0.000846 seconds
|
|
211
205
|
3 contexts, 4 specifications, 0 failures
|
212
206
|
</pre>
|
213
207
|
|
214
|
-
Now let's use
|
208
|
+
Now let's use the item to determine "emptiness"...
|
215
209
|
|
216
210
|
<ruby>
|
217
211
|
class Stack
|
@@ -238,7 +232,6 @@ A new stack
|
|
238
232
|
- should be empty
|
239
233
|
|
240
234
|
An empty stack
|
241
|
-
- should keep its mouth shut when you send it 'push'
|
242
235
|
- should not be empty after 'push'
|
243
236
|
|
244
237
|
A stack with one item
|
@@ -272,7 +265,6 @@ A new stack
|
|
272
265
|
- should be empty
|
273
266
|
|
274
267
|
An empty stack
|
275
|
-
- should keep its mouth shut when you send it 'push'
|
276
268
|
- should not be empty after 'push'
|
277
269
|
|
278
270
|
A stack with one item
|
@@ -283,7 +275,7 @@ Finished in 0.000737 seconds
|
|
283
275
|
3 contexts, 4 specifications, 0 failures
|
284
276
|
</pre>
|
285
277
|
|
286
|
-
|
278
|
+
So this time we were able to refactor, and in doing so not only reduce the duplication but also reduce the size of the stack class. Sweet.
|
287
279
|
|
288
280
|
To be continued...
|
289
281
|
|
@@ -1,4 +1,4 @@
|
|
1
|
-
h2. A Simple Stack - when a new expectation passes
|
1
|
+
h2. A Simple Stack - when a new expectation passes - IN PROGRESS - DISREGARD THIS PAGE
|
2
2
|
|
3
3
|
At this point stack_spec.rb should look like this...
|
4
4
|
|
@@ -20,10 +20,6 @@ context "An empty stack" do
|
|
20
20
|
@stack = Stack.new
|
21
21
|
end
|
22
22
|
|
23
|
-
specify "should keep its mouth shut when you send it 'push'" do
|
24
|
-
lambda { @stack.push Object.new }.should.not.raise
|
25
|
-
end
|
26
|
-
|
27
23
|
specify "should not be empty after 'push'" do
|
28
24
|
@stack.push 37
|
29
25
|
@stack.should_not_be_empty
|
@@ -67,7 +63,6 @@ A new stack
|
|
67
63
|
- should be empty
|
68
64
|
|
69
65
|
An empty stack
|
70
|
-
- should keep its mouth shut when you send it 'push'
|
71
66
|
- should not be empty after 'push'
|
72
67
|
|
73
68
|
A stack with one item
|
@@ -78,7 +73,11 @@ Finished in 0.000741 seconds
|
|
78
73
|
3 contexts, 4 specifications, 0 failures
|
79
74
|
</pre>
|
80
75
|
|
81
|
-
Again, a really nice feature of using the <code>--format specdoc</code> option (<code>-f s</code> for short) is that you can
|
76
|
+
Again, a really nice feature of using the <code>--format specdoc</code> option (<code>-f s</code> for short) is that you can see the big picture very clearly.
|
77
|
+
|
78
|
+
Look closely at the "An empty stack" context. We say that it "should not be empty after 'push'". Does that strike you as confusing? It may not, but if you think about it, we're taking an object in one state ("An empty stack"), changing its state by pushing an item onto it and THEN setting an expectation about it. You could argue that we're not really specifying behaviour of an empty stack at all here, but rather behaviour of a stack with one element when you call push.
|
79
|
+
|
80
|
+
So let's add that spec to "A stack with one item".
|
82
81
|
|
83
82
|
<ruby>
|
84
83
|
context "A stack with one item" do
|
@@ -86,11 +85,12 @@ context "A stack with one item" do
|
|
86
85
|
@stack = Stack.new
|
87
86
|
@stack.push "one item"
|
88
87
|
end
|
88
|
+
|
89
|
+
specify "should return top when you send it 'top'" do
|
90
|
+
@stack.top.should_equal "one item"
|
91
|
+
end
|
89
92
|
|
90
|
-
|
91
|
-
|
92
|
-
specify "should not be empty after 'top'" do
|
93
|
-
@stack.top
|
93
|
+
specify "should not be empty" do
|
94
94
|
@stack.should_not_be_empty
|
95
95
|
end
|
96
96
|
end
|
@@ -103,101 +103,62 @@ A new stack
|
|
103
103
|
- should be empty
|
104
104
|
|
105
105
|
An empty stack
|
106
|
-
- should keep its mouth shut when you send it 'push'
|
107
106
|
- should not be empty after 'push'
|
108
107
|
|
109
108
|
A stack with one item
|
110
109
|
- should return top when you send it 'top'
|
111
|
-
- should not be empty
|
110
|
+
- should not be empty
|
112
111
|
|
113
|
-
Finished in 0.
|
112
|
+
Finished in 0.000849 seconds
|
114
113
|
|
115
|
-
3 contexts,
|
114
|
+
3 contexts, 4 specifications, 0 failures
|
116
115
|
</pre>
|
117
116
|
|
118
|
-
|
119
|
-
|
120
|
-
In this case, the simplest way to approach this is to return <code>true</code> from <code>empty?</code>.
|
117
|
+
And now we can just remove "An empty spec" from stack_spec.rb.
|
121
118
|
|
122
119
|
<ruby>
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
def push item
|
129
|
-
@item = item
|
120
|
+
require 'stack'
|
121
|
+
|
122
|
+
context "A new stack" do
|
123
|
+
setup do
|
124
|
+
@stack = Stack.new
|
130
125
|
end
|
131
|
-
|
132
|
-
|
126
|
+
specify "should be empty" do
|
127
|
+
@stack.should_be_empty
|
133
128
|
end
|
134
129
|
end
|
135
|
-
</ruby>
|
136
|
-
<br>
|
137
|
-
<pre>
|
138
|
-
$ spec stack_spec.rb -f s -s "A stack with one item should not be empty after 'top'"
|
139
|
-
|
140
|
-
A stack with one item
|
141
|
-
- should not be empty after 'top' (FAILED - 1)
|
142
|
-
|
143
|
-
1)
|
144
|
-
ExpectationNotMetError in 'A stack with one item should not be empty after 'top''
|
145
|
-
Stack #<Stack:0x36ad18 @item="one item"> should not be empty
|
146
|
-
./stack_spec.rb:39:in `should not be empty after 'top''
|
147
|
-
|
148
|
-
Finished in 0.000398 seconds
|
149
130
|
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
The failure tells us that there was an ExpectationNotMetError, as we expected. Revert the code ...
|
131
|
+
context "A stack with one item" do
|
132
|
+
setup do
|
133
|
+
@stack = Stack.new
|
134
|
+
@stack.push "one item"
|
135
|
+
end
|
156
136
|
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
137
|
+
specify "should return top when you send it 'top'" do
|
138
|
+
@stack.top.should_equal "one item"
|
139
|
+
end
|
140
|
+
|
141
|
+
specify "should not be empty" do
|
142
|
+
@stack.should_not_be_empty
|
161
143
|
end
|
162
|
-
...
|
163
144
|
end
|
164
145
|
</ruby>
|
165
|
-
|
166
|
-
... run the single spec ...
|
167
|
-
|
168
|
-
<pre>
|
169
|
-
$ spec stack_spec.rb -f s -s "A stack with one item should not be empty after 'top'"
|
170
|
-
|
171
|
-
A stack with one item
|
172
|
-
- should not be empty after 'top'
|
173
|
-
|
174
|
-
Finished in 0.00028 seconds
|
175
|
-
|
176
|
-
1 context, 1 specification, 0 failures
|
177
|
-
</pre>
|
178
|
-
|
179
|
-
... and then run all the specs ...
|
180
|
-
|
146
|
+
<br>
|
181
147
|
<pre>
|
182
148
|
$ spec stack_spec.rb -f s
|
183
149
|
|
184
150
|
A new stack
|
185
151
|
- should be empty
|
186
152
|
|
187
|
-
An empty stack
|
188
|
-
- should keep its mouth shut when you send it 'push'
|
189
|
-
- should not be empty after 'push'
|
190
|
-
|
191
153
|
A stack with one item
|
192
154
|
- should return top when you send it 'top'
|
193
|
-
- should not be empty
|
155
|
+
- should not be empty
|
194
156
|
|
195
|
-
Finished in 0.
|
157
|
+
Finished in 0.000565 seconds
|
196
158
|
|
197
|
-
|
159
|
+
2 contexts, 3 specifications, 0 failures
|
198
160
|
</pre>
|
199
161
|
|
200
|
-
|
162
|
+
So keep your eye on the contexts and specifications as they evolve. Don't be afraid to move specs around. There are many different benefits that we get from these executable specifications. One is that it helps us to drive code, resulting in very simple and well tested code. Another very important benefit is that future developers can look at them and understand how to use a component (module, class, method, etc). Keep them in mind. "They" may even be you!
|
201
163
|
|
202
|
-
<a href="stack_03.html">Previous</a>
|
203
|
-
<a href="stack_05.html">Next</a>
|
164
|
+
<a href="stack_03.html">Previous</a>
|
@@ -4,38 +4,22 @@ context "A new stack" do
|
|
4
4
|
setup do
|
5
5
|
@stack = Stack.new
|
6
6
|
end
|
7
|
-
|
8
7
|
specify "should be empty" do
|
9
8
|
@stack.should_be_empty
|
10
9
|
end
|
11
10
|
end
|
12
11
|
|
13
|
-
context "An empty stack" do
|
14
|
-
setup do
|
15
|
-
@stack = Stack.new
|
16
|
-
end
|
17
|
-
|
18
|
-
specify "should keep its mouth shut when you send it 'push'" do
|
19
|
-
lambda { @stack.push Object.new }.should.not.raise
|
20
|
-
end
|
21
|
-
end
|
22
|
-
|
23
12
|
context "A stack with one item" do
|
24
13
|
setup do
|
25
14
|
@stack = Stack.new
|
26
15
|
@stack.push "one item"
|
27
16
|
end
|
28
17
|
|
29
|
-
specify "should not be empty" do
|
30
|
-
@stack.should_not_be_empty
|
31
|
-
end
|
32
|
-
|
33
18
|
specify "should return top when you send it 'top'" do
|
34
19
|
@stack.top.should_equal "one item"
|
35
20
|
end
|
36
21
|
|
37
|
-
specify "should not be empty
|
38
|
-
@stack.top
|
22
|
+
specify "should not be empty" do
|
39
23
|
@stack.should_not_be_empty
|
40
24
|
end
|
41
|
-
end
|
25
|
+
end
|
@@ -10,7 +10,7 @@ module RCov
|
|
10
10
|
# Defaults to 'coverage/index.html'
|
11
11
|
attr_accessor :index_html
|
12
12
|
|
13
|
-
# Whether or not to output details
|
13
|
+
# Whether or not to output details. Defaults to true.
|
14
14
|
attr_accessor :verbose
|
15
15
|
|
16
16
|
# The threshold value (in percent) for coverage. If the
|
@@ -21,7 +21,7 @@ module RCov
|
|
21
21
|
def initialize(name=:rcov_verify)
|
22
22
|
@name = name
|
23
23
|
@index_html = 'coverage/index.html'
|
24
|
-
@verbose =
|
24
|
+
@verbose = true
|
25
25
|
yield self if block_given?
|
26
26
|
raise "Threshold must be set" if @threshold.nil?
|
27
27
|
define
|
data/lib/spec/rake/spectask.rb
CHANGED
@@ -82,6 +82,9 @@ module Rake
|
|
82
82
|
lib_path = @libs.join(File::PATH_SEPARATOR)
|
83
83
|
desc "Run specs" + (@name==:spec ? "" : " for #{@name}")
|
84
84
|
task @name do
|
85
|
+
specs = file_list
|
86
|
+
raise "No spec files found." if specs.empty?
|
87
|
+
|
85
88
|
spec = File.dirname(__FILE__) + '/../../../bin/spec'
|
86
89
|
file_prefix = @rcov ? " -- " : ""
|
87
90
|
interpreter = @rcov ? "rcov" : "ruby"
|
@@ -94,7 +97,7 @@ module Rake
|
|
94
97
|
" \"#{spec}\" " +
|
95
98
|
" #{@spec_opts.join(' ')} " +
|
96
99
|
file_prefix +
|
97
|
-
|
100
|
+
specs.collect { |fn| "\"#{fn}\"" }.join(' ') +
|
98
101
|
redirect
|
99
102
|
end
|
100
103
|
self
|
@@ -111,14 +114,6 @@ module Rake
|
|
111
114
|
end
|
112
115
|
end
|
113
116
|
|
114
|
-
def find_file(fn) # :nodoc:
|
115
|
-
$LOAD_PATH.each do |path|
|
116
|
-
file_path = File.join(path, "#{fn}.rb")
|
117
|
-
return file_path if File.exist? file_path
|
118
|
-
end
|
119
|
-
nil
|
120
|
-
end
|
121
|
-
|
122
117
|
def run(interpreter, *args, &block)
|
123
118
|
if Hash === args.last
|
124
119
|
options = args.pop
|
data/lib/spec/runner.rb
CHANGED
@@ -27,6 +27,8 @@ module Spec
|
|
27
27
|
line = nil if line =~ /\/lib\/spec\/api\//
|
28
28
|
line = nil if line =~ /\/lib\/spec\/runner\//
|
29
29
|
line = nil if line =~ /bin\/spec:/
|
30
|
+
# TextMate's Ruby plugin
|
31
|
+
line = nil if line =~ /Ruby\.tmbundle\/Support\/tmruby.rb:/
|
30
32
|
line
|
31
33
|
end
|
32
34
|
error.backtrace.compact!
|
data/lib/spec/runner/context.rb
CHANGED
@@ -32,17 +32,19 @@ module Spec
|
|
32
32
|
@specifications.length
|
33
33
|
end
|
34
34
|
|
35
|
-
def matches? name
|
36
|
-
|
35
|
+
def matches? name, matcher=nil
|
36
|
+
matcher ||= SpecMatcher.new name, @name
|
37
37
|
@specifications.each do |spec|
|
38
|
-
return true if spec.
|
38
|
+
return true if spec.matches_matcher? matcher
|
39
39
|
end
|
40
40
|
return false
|
41
41
|
end
|
42
42
|
|
43
|
-
def
|
43
|
+
def run_single_spec name
|
44
|
+
return if @name == name
|
45
|
+
matcher = SpecMatcher.new name, @name
|
44
46
|
@specifications.reject! do |spec|
|
45
|
-
!spec.
|
47
|
+
!spec.matches_matcher? matcher
|
46
48
|
end
|
47
49
|
end
|
48
50
|
end
|