rspec 0.5.2 → 0.5.3
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGES +10 -2
- data/Rakefile +22 -30
- data/doc/src/default.css +11 -10
- data/doc/src/documentation/api.page +15 -82
- data/doc/src/documentation/mocks.page +12 -55
- data/doc/src/meta.info +4 -1
- data/examples/airport_spec.rb +0 -1
- data/examples/empty_stack_spec.rb +1 -0
- data/examples/stack_spec.rb +1 -0
- data/examples/team_spec.rb +30 -0
- data/lib/spec/api.rb +1 -0
- data/lib/spec/api/duck_type.rb +16 -0
- data/lib/spec/api/expectations.rb +4 -4
- data/lib/spec/api/mock.rb +1 -0
- data/lib/spec/runner/backtrace_tweaker.rb +1 -2
- data/lib/spec/runner/context.rb +2 -3
- data/lib/spec/runner/context_runner.rb +2 -2
- data/lib/spec/runner/execution_context.rb +4 -0
- data/lib/spec/runner/option_parser.rb +3 -2
- data/lib/spec/runner/simple_text_reporter.rb +11 -25
- data/lib/spec/runner/specification.rb +1 -2
- data/lib/spec/version.rb +1 -1
- data/test/{rake → rcov}/rcov_testtask.rb +4 -4
- data/test/rcov/rcov_verify.rb +28 -0
- data/test/spec/api/duck_type_test.rb +19 -0
- data/test/spec/api/mock_arg_constraints_test.rb +20 -0
- data/test/spec/runner/backtrace_tweaker_test.rb +16 -8
- data/test/spec/runner/context_runner_test.rb +3 -3
- data/test/spec/runner/context_test.rb +2 -2
- data/test/spec/runner/execution_context_test.rb +7 -0
- data/test/spec/runner/option_parser_test.rb +12 -2
- data/test/spec/runner/simple_text_reporter_test.rb +18 -47
- data/test/spec/runner/specification_test.rb +5 -5
- data/test/spec/tool/command_line_test.rb +0 -1
- data/test/test_helper.rb +1 -0
- metadata +9 -7
- data/doc/src/download.page +0 -7
@@ -9,31 +9,21 @@ RSpec contains a full featured Mock Objects framework.
|
|
9
9
|
h3. Creating a mock
|
10
10
|
|
11
11
|
<pre>
|
12
|
-
<code>
|
13
12
|
mock(<name>)
|
14
|
-
</code>
|
15
13
|
</pre>
|
16
14
|
|
17
|
-
This creates a new mock with the given name (a string) and registers it. When
|
18
|
-
the specification finishes, all registered mocks are verified.
|
15
|
+
This creates a new mock with the given name (a string) and registers it. When the specification finishes, all registered mocks are verified.
|
19
16
|
|
20
17
|
<pre>
|
21
|
-
<code>
|
22
18
|
mock(<name>, <options>)
|
23
|
-
</code>
|
24
19
|
</pre>
|
25
20
|
|
26
|
-
As above, but allows you to specific options to tweak the mock's behaviour.
|
27
|
-
The <code>options</code> argument is a hash. Currently the only supported option is
|
28
|
-
<code>:null_object</code>. Setting this to true (i.e. <code>:null_object => true</code>) instructs the
|
29
|
-
mock to ignore (quietly consume) any messages it hasn't been told to expect.
|
21
|
+
As above, but allows you to specific options to tweak the mock's behaviour. The <code>options</code> argument is a hash. Currently the only supported option is <code>:null_object</code>. Setting this to true (i.e. <code>:null_object => true</code>) instructs the mock to ignore (quietly consume) any messages it hasn't been told to expect.
|
30
22
|
|
31
23
|
h3. Expecting Messages
|
32
24
|
|
33
25
|
<pre>
|
34
|
-
<code>
|
35
26
|
mock.should.receive(<message>)
|
36
|
-
</code>
|
37
27
|
</pre>
|
38
28
|
|
39
29
|
The <code>message</code> argument is a symbol that is the name of a message that you want
|
@@ -46,9 +36,7 @@ by the mock, the block is evaluated, and passed any arguments. The result is
|
|
46
36
|
the return value of the message. For example:
|
47
37
|
|
48
38
|
<pre>
|
49
|
-
<code>
|
50
39
|
@mock.should.receive(:random_call) {| a | a.should.be true}
|
51
|
-
</code>
|
52
40
|
</pre>
|
53
41
|
|
54
42
|
This allows arbitrary argument validation and result computation.
|
@@ -56,27 +44,21 @@ This allows arbitrary argument validation and result computation.
|
|
56
44
|
h3. Expecting Arguments
|
57
45
|
|
58
46
|
<pre>
|
59
|
-
<code>
|
60
47
|
mock.should.receive(:msg).with(<args>)
|
61
48
|
mock.should.receive(:msg).with(1, 2, 3)
|
62
|
-
</code>
|
63
49
|
</pre>
|
64
50
|
|
65
51
|
The <code>args</code> argument is a series of arguments (e..g. 1, 2, 3) that are expected
|
66
52
|
to be passed as arguments to the associated message.
|
67
53
|
|
68
54
|
<pre>
|
69
|
-
<code>
|
70
55
|
mock.should.receive(:msg).with(:no_args)
|
71
|
-
</code>
|
72
56
|
</pre>
|
73
57
|
|
74
58
|
No arguments are to be accepted by the message.
|
75
59
|
|
76
60
|
<pre>
|
77
|
-
<code>
|
78
61
|
mock.should.receive(:msg).with(:any_args)
|
79
|
-
</code>
|
80
62
|
</pre>
|
81
63
|
|
82
64
|
Any arguments are to be accepted by the message. This includes cases where no
|
@@ -92,9 +74,7 @@ h4. :anything
|
|
92
74
|
accepts any value for this argument
|
93
75
|
|
94
76
|
<pre>
|
95
|
-
<code>
|
96
77
|
mock.should.receive(:msg).with(1, :anything, "A")
|
97
|
-
</code>
|
98
78
|
</pre>
|
99
79
|
|
100
80
|
h4. :numeric
|
@@ -102,9 +82,7 @@ h4. :numeric
|
|
102
82
|
accepts any numeric value for this argument
|
103
83
|
|
104
84
|
<pre>
|
105
|
-
<code>
|
106
85
|
mock.should.receive(:msg).with(a, :numeric, "b")
|
107
|
-
</code>
|
108
86
|
</pre>
|
109
87
|
|
110
88
|
h4. :boolean
|
@@ -112,9 +90,7 @@ h4. :boolean
|
|
112
90
|
accepts a boolean value for this argument
|
113
91
|
|
114
92
|
<pre>
|
115
|
-
<code>
|
116
93
|
mock.should.receive(:msg).with(a, :boolean, "b")
|
117
|
-
</code>
|
118
94
|
</pre>
|
119
95
|
|
120
96
|
h4. :string
|
@@ -122,74 +98,65 @@ h4. :string
|
|
122
98
|
accepts any string for this argument
|
123
99
|
|
124
100
|
<pre>
|
125
|
-
<code>
|
126
101
|
mock.should.receive(:msg).with(a, :string, "b")
|
127
|
-
</code>
|
128
102
|
</pre>
|
129
103
|
|
104
|
+
h4. duck_type(message(s))
|
105
|
+
|
106
|
+
accepts any object that responds to the prescribed message(s)
|
107
|
+
|
108
|
+
<pre>
|
109
|
+
#accepts a Fixnum for the second arg
|
110
|
+
mock.should.receive(:msg).with(a, duck_type(:abs, :div), "b")
|
111
|
+
</pre>
|
112
|
+
|
130
113
|
h3. Receive Counts
|
131
114
|
|
132
115
|
<pre>
|
133
|
-
<code>
|
134
116
|
mock.should.receive(:msg).never
|
135
|
-
</code>
|
136
117
|
</pre>
|
137
118
|
|
138
119
|
A problem is reported if the message is ever received.
|
139
120
|
|
140
121
|
<pre>
|
141
|
-
<code>
|
142
122
|
mock.should.receive(:msg).any.number.of.times
|
143
|
-
</code>
|
144
123
|
</pre>
|
145
124
|
|
146
125
|
The message can be received 0 or more times.
|
147
126
|
|
148
127
|
<pre>
|
149
|
-
<code>
|
150
128
|
mock.should.receive(:msg).once
|
151
|
-
</code>
|
152
129
|
</pre>
|
153
130
|
|
154
131
|
A problem is reported is the message is never received, or it is received more
|
155
132
|
than once.
|
156
133
|
|
157
134
|
<pre>
|
158
|
-
<code>
|
159
135
|
mock.should.receive(:msg).twice
|
160
|
-
</code>
|
161
136
|
</pre>
|
162
137
|
|
163
138
|
A problem is reported is the message is received anything but two times.
|
164
139
|
|
165
140
|
<pre>
|
166
|
-
<code>
|
167
141
|
mock.should.receive(:msg).exactly(n).times
|
168
|
-
</code>
|
169
142
|
</pre>
|
170
143
|
|
171
144
|
A problem is reported is the message is received anything but n times.
|
172
145
|
|
173
146
|
<pre>
|
174
|
-
<code>
|
175
147
|
mock.should.receive(:msg).at.least(:once)
|
176
|
-
</code>
|
177
148
|
</pre>
|
178
149
|
|
179
150
|
A problem is reported if the message is never received.
|
180
151
|
|
181
152
|
<pre>
|
182
|
-
<code>
|
183
153
|
mock.should.receive(:msg).at.least(:twice)
|
184
|
-
</code>
|
185
154
|
</pre>
|
186
155
|
|
187
156
|
A problem is reported is the message is never received or is received only once.
|
188
157
|
|
189
158
|
<pre>
|
190
|
-
<code>
|
191
159
|
mock.should.receive(:msg).at.least(n).times
|
192
|
-
</code>
|
193
160
|
</pre>
|
194
161
|
|
195
162
|
A problem is reported is the message is received fewer than n times.
|
@@ -197,27 +164,21 @@ A problem is reported is the message is received fewer than n times.
|
|
197
164
|
h3. Return Values
|
198
165
|
|
199
166
|
<pre>
|
200
|
-
<code>
|
201
167
|
mock.should.receive(:msg).once.and.return(<value>)
|
202
|
-
</code>
|
203
168
|
</pre>
|
204
169
|
|
205
170
|
When the expected message is received, <code>value</code> will be returned as the result.
|
206
171
|
|
207
172
|
<pre>
|
208
|
-
<code>
|
209
173
|
and.return([<value-1>, <value-2>, ..., <value-n>])
|
210
|
-
</code>
|
211
174
|
</pre>
|
212
175
|
|
213
176
|
When the expected message is received, <code>value-i</code> will be returned as the result
|
214
|
-
for the ith reception of the message. Once i > n
|
177
|
+
for the ith reception of the message. Once <code>i > n</code>, <code>value-n</code> is returned for all
|
215
178
|
subsequent receives of the message.
|
216
179
|
|
217
180
|
<pre>
|
218
|
-
<code>
|
219
181
|
mock.should.receive(:msg).once.and.return {...}
|
220
|
-
</code>
|
221
182
|
</pre>
|
222
183
|
|
223
184
|
When the expected message is received, the result of evaluating the supplied
|
@@ -226,18 +187,14 @@ as parts of the message. This capability can be used to compute return values
|
|
226
187
|
based on the arguments. For example:
|
227
188
|
|
228
189
|
<pre>
|
229
|
-
<code>
|
230
190
|
mock.should.receive(:msg).once.and.return {|a, b| a + b}
|
231
|
-
</code>
|
232
191
|
</pre>
|
233
192
|
|
234
193
|
h3. Raising and Throwing
|
235
194
|
|
236
195
|
<pre>
|
237
|
-
<code>
|
238
196
|
mock.should.receive(:msg).once.and.raise(<exception>)
|
239
197
|
mock.should.receive(:msg).once.and.throw(<symbol>)
|
240
|
-
</code>
|
241
198
|
</pre>
|
242
199
|
|
243
200
|
These instruct the mock to raise an exception or throw a symbol instead of returning a value.
|
data/doc/src/meta.info
CHANGED
data/examples/airport_spec.rb
CHANGED
data/examples/stack_spec.rb
CHANGED
@@ -0,0 +1,30 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../lib/spec'
|
2
|
+
|
3
|
+
class Team
|
4
|
+
attr_reader :players
|
5
|
+
def initialize
|
6
|
+
@players = Players.new
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
class Players
|
11
|
+
def size
|
12
|
+
0
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
context "A new team" do
|
17
|
+
|
18
|
+
setup do
|
19
|
+
@team = Team.new
|
20
|
+
end
|
21
|
+
|
22
|
+
specify "should have 3 players (failing example)" do
|
23
|
+
@team.should.have(3).players
|
24
|
+
end
|
25
|
+
|
26
|
+
specify "should have 1 player (failing example)" do
|
27
|
+
@team.players.size.should.be 1
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
data/lib/spec/api.rb
CHANGED
@@ -0,0 +1,16 @@
|
|
1
|
+
module Spec
|
2
|
+
module Api
|
3
|
+
|
4
|
+
class DuckType
|
5
|
+
def initialize(*methods_to_respond_do)
|
6
|
+
@methods_to_respond_do = methods_to_respond_do
|
7
|
+
end
|
8
|
+
|
9
|
+
def walks_like?(obj)
|
10
|
+
@methods_to_respond_do.each { |sym| return false unless obj.respond_to? sym }
|
11
|
+
return true
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
end
|
16
|
+
end
|
data/lib/spec/api/mock.rb
CHANGED
@@ -88,6 +88,7 @@ module Spec
|
|
88
88
|
next if @expected_params[i] == :numeric and args[i].is_a?Numeric
|
89
89
|
next if @expected_params[i] == :boolean and args[i].is_a?TrueClass or args[i].is_a?FalseClass
|
90
90
|
next if @expected_params[i] == :string and args[i].is_a?String
|
91
|
+
next if @expected_params[i].is_a? DuckType and @expected_params[i].walks_like? args[i]
|
91
92
|
return false unless args[i] == @expected_params[i]
|
92
93
|
end
|
93
94
|
return true
|
@@ -5,8 +5,7 @@ module Spec
|
|
5
5
|
return if error.backtrace.nil?
|
6
6
|
error.backtrace.collect! do |line|
|
7
7
|
line = line.split(':in')[0] + ":in `#{spec_name}'" if line.include?('__instance_exec')
|
8
|
-
line = nil if line
|
9
|
-
line = nil if line.include? '/lib/spec/api/helper/should_negator.rb' unless line.nil?
|
8
|
+
line = nil if line =~ /\/lib\/spec\/api\/helper\/.+[helper|base|negator].rb/
|
10
9
|
line
|
11
10
|
end
|
12
11
|
error.backtrace.compact!
|
data/lib/spec/runner/context.rb
CHANGED
@@ -13,13 +13,12 @@ module Spec
|
|
13
13
|
@specifications = []
|
14
14
|
@name = name
|
15
15
|
instance_exec(&context_block)
|
16
|
-
@@context_runner.add_context(self) unless @@context_runner.nil?
|
17
16
|
ContextRunner.standalone(self) if @@context_runner.nil?
|
18
|
-
|
17
|
+
@@context_runner.add_context(self) unless @@context_runner.nil?
|
19
18
|
end
|
20
19
|
|
21
20
|
def run(reporter)
|
22
|
-
reporter.add_context(@name
|
21
|
+
reporter.add_context(@name)
|
23
22
|
@specifications.each do |specification|
|
24
23
|
specification.run(reporter, @setup_block, @teardown_block)
|
25
24
|
end
|
@@ -4,8 +4,8 @@ module Spec
|
|
4
4
|
module Runner
|
5
5
|
class ContextRunner
|
6
6
|
|
7
|
-
def self.standalone
|
8
|
-
context_runner = ContextRunner.new(
|
7
|
+
def self.standalone(context, args=ARGV)
|
8
|
+
context_runner = ContextRunner.new(args, true)
|
9
9
|
context_runner.add_context context
|
10
10
|
context_runner.run
|
11
11
|
end
|
@@ -15,7 +15,8 @@ module Spec
|
|
15
15
|
opts.separator ""
|
16
16
|
|
17
17
|
opts.on("-o", "--of [FILE]", "Set the output file (defaults to STDOUT)") do |outfile|
|
18
|
-
options.out = outfile
|
18
|
+
options.out = StringIO.new if outfile == "stringio"
|
19
|
+
options.out = outfile unless outfile.nil? or outfile == "stringio"
|
19
20
|
exit if outfile.nil?
|
20
21
|
end
|
21
22
|
|
@@ -33,7 +34,7 @@ module Spec
|
|
33
34
|
end
|
34
35
|
|
35
36
|
opts.on_tail("-h", "--help", "Show this message") do
|
36
|
-
|
37
|
+
out.puts opts
|
37
38
|
exit if out == $stdout
|
38
39
|
end
|
39
40
|
|
@@ -6,24 +6,23 @@ module Spec
|
|
6
6
|
@context_names = []
|
7
7
|
@errors = []
|
8
8
|
@spec_names = []
|
9
|
-
@failures = []
|
10
9
|
@verbose = verbose
|
11
10
|
@backtrace_tweaker = backtrace_tweaker
|
12
11
|
end
|
13
12
|
|
14
|
-
def add_context(name
|
13
|
+
def add_context(name)
|
15
14
|
@output << "\n" if @context_names.empty? unless @verbose
|
16
15
|
@output << "\n#{name}\n" if @verbose
|
17
|
-
@context_names <<
|
16
|
+
@context_names << name
|
18
17
|
end
|
19
18
|
|
20
|
-
def add_spec(name,
|
19
|
+
def add_spec(name, errors=[])
|
21
20
|
if errors.empty?
|
22
21
|
spec_passed(name)
|
23
22
|
else
|
24
23
|
errors.each { |error| @backtrace_tweaker.tweak_backtrace(error, name) }
|
25
24
|
# only show the first one (there might be more)
|
26
|
-
spec_failed(name,
|
25
|
+
spec_failed(name, errors[0])
|
27
26
|
end
|
28
27
|
end
|
29
28
|
|
@@ -37,7 +36,7 @@ module Spec
|
|
37
36
|
|
38
37
|
def dump
|
39
38
|
@output << "\n"
|
40
|
-
|
39
|
+
dump_errors
|
41
40
|
@output << "\n\n" unless @errors.empty?
|
42
41
|
@output << "\n" if @errors.empty?
|
43
42
|
@output << "Finished in " << (duration).to_s << " seconds\n\n"
|
@@ -47,16 +46,14 @@ module Spec
|
|
47
46
|
@output << "\n"
|
48
47
|
end
|
49
48
|
|
50
|
-
def
|
49
|
+
def dump_errors
|
51
50
|
return if @errors.empty?
|
52
51
|
@output << "\n"
|
53
|
-
@
|
52
|
+
@errors.inject(1) do |index, error|
|
54
53
|
@output << "\n\n" if index > 1
|
55
54
|
@output << index.to_s << ")\n"
|
56
|
-
@output << "#{
|
57
|
-
|
58
|
-
@output << "Specification: #{failure.spec_name} [#{failure.spec_line}]\n"
|
59
|
-
dump_backtrace(failure.error.backtrace)
|
55
|
+
@output << "#{error.message} (#{error.class.name})\n"
|
56
|
+
dump_backtrace(error.backtrace)
|
60
57
|
index + 1
|
61
58
|
end
|
62
59
|
end
|
@@ -78,25 +75,14 @@ module Spec
|
|
78
75
|
@output << '.' unless @verbose
|
79
76
|
end
|
80
77
|
|
81
|
-
def spec_failed(name,
|
78
|
+
def spec_failed(name, error)
|
82
79
|
@spec_names << name
|
83
80
|
@errors << error
|
84
|
-
@
|
85
|
-
@output << "- #{name} (FAILED - #{@failures.length})\n" if @verbose
|
81
|
+
@output << "- #{name} (FAILED - #{@errors.length})\n" if @verbose
|
86
82
|
@output << 'F' unless @verbose
|
87
83
|
end
|
88
84
|
|
89
85
|
end
|
90
86
|
|
91
|
-
class Failure
|
92
|
-
attr_reader :context_name, :context_line, :spec_name, :spec_line, :error
|
93
|
-
def initialize(context_name, context_line, spec_name, spec_line, error)
|
94
|
-
@context_name = context_name
|
95
|
-
@context_line = context_line
|
96
|
-
@spec_name = spec_name
|
97
|
-
@spec_line = spec_line
|
98
|
-
@error = error
|
99
|
-
end
|
100
|
-
end
|
101
87
|
end
|
102
88
|
end
|