rspec 0.5.2 → 0.5.3
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/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
|