Blob of rspec/spec/spec/mocks/mock_spec.rb (raw blob data)

1 require File.dirname(__FILE__) + '/../../spec_helper'
2
3 module Spec
4 module Mocks
5 describe Mock do
6
7 before(:each) do
8 @mock = mock("test mock")
9 end
10
11 after(:each) do
12 @mock.rspec_reset
13 end
14
15 it "should report line number of expectation of unreceived message" do
16 expected_error_line = __LINE__; @mock.should_receive(:wont_happen).with("x", 3)
17 begin
18 @mock.rspec_verify
19 violated
20 rescue MockExpectationError => e
21 # NOTE - this regexp ended w/ $, but jruby adds extra info at the end of the line
22 e.backtrace[0].should match(/#{File.basename(__FILE__)}:#{expected_error_line}/)
23 end
24 end
25
26 it "should pass when not receiving message specified as not to be received" do
27 @mock.should_not_receive(:not_expected)
28 @mock.rspec_verify
29 end
30
31 it "should pass when receiving message specified as not to be received with different args" do
32 @mock.should_not_receive(:message).with("unwanted text")
33 @mock.should_receive(:message).with("other text")
34 @mock.message "other text"
35 @mock.rspec_verify
36 end
37
38 it "should fail when receiving message specified as not to be received" do
39 @mock.should_not_receive(:not_expected)
40 lambda {
41 @mock.not_expected
42 violated
43 }.should raise_error(MockExpectationError, "Mock 'test mock' expected :not_expected with (no args) 0 times, but received it once")
44 end
45
46 it "should fail when receiving message specified as not to be received with args" do
47 @mock.should_not_receive(:not_expected).with("unexpected text")
48 lambda {
49 @mock.not_expected("unexpected text")
50 violated
51 }.should raise_error(MockExpectationError, "Mock 'test mock' expected :not_expected with (\"unexpected text\") 0 times, but received it once")
52 end
53
54 it "should pass when receiving message specified as not to be received with wrong args" do
55 @mock.should_not_receive(:not_expected).with("unexpected text")
56 @mock.not_expected "really unexpected text"
57 @mock.rspec_verify
58 end
59
60 it "should allow block to calculate return values" do
61 @mock.should_receive(:something).with("a","b","c").and_return { |a,b,c| c+b+a }
62 @mock.something("a","b","c").should == "cba"
63 @mock.rspec_verify
64 end
65
66 it "should allow parameter as return value" do
67 @mock.should_receive(:something).with("a","b","c").and_return("booh")
68 @mock.something("a","b","c").should == "booh"
69 @mock.rspec_verify
70 end
71
72 it "should return nil if no return value set" do
73 @mock.should_receive(:something).with("a","b","c")
74 @mock.something("a","b","c").should be_nil
75 @mock.rspec_verify
76 end
77
78 it "should raise exception if args don't match when method called" do
79 @mock.should_receive(:something).with("a","b","c").and_return("booh")
80 lambda {
81 @mock.something("a","d","c")
82 violated
83 }.should raise_error(MockExpectationError, "Mock 'test mock' expected :something with (\"a\", \"b\", \"c\") but received it with (\"a\", \"d\", \"c\")")
84 end
85
86 it "should raise exception if args don't match when method called even when the method is stubbed" do
87 @mock.stub!(:something)
88 @mock.should_receive(:something).with("a","b","c")
89 lambda {
90 @mock.something("a","d","c")
91 @mock.rspec_verify
92 }.should raise_error(MockExpectationError, "Mock 'test mock' expected :something with (\"a\", \"b\", \"c\") but received it with (\"a\", \"d\", \"c\")")
93 end
94
95 it "should fail if unexpected method called" do
96 lambda {
97 @mock.something("a","b","c")
98 violated
99 }.should raise_error(MockExpectationError, "Mock 'test mock' received unexpected message :something with (\"a\", \"b\", \"c\")")
100 end
101
102 it "should use block for expectation if provided" do
103 @mock.should_receive(:something) do | a, b |
104 a.should == "a"
105 b.should == "b"
106 "booh"
107 end
108 @mock.something("a", "b").should == "booh"
109 @mock.rspec_verify
110 end
111
112 it "should fail if expectation block fails" do
113 @mock.should_receive(:something) {| bool | bool.should be_true}
114 lambda {
115 @mock.something false
116 }.should raise_error(MockExpectationError, /Mock 'test mock' received :something but passed block failed with: expected true, got false/)
117 end
118
119 it "should fail right away when method defined as never is received" do
120 @mock.should_receive(:not_expected).never
121 lambda {
122 @mock.not_expected
123 }.should raise_error(MockExpectationError, "Mock 'test mock' expected :not_expected with (no args) 0 times, but received it once")
124 end
125
126 it "should eventually fail when method defined as never is received" do
127 @mock.should_receive(:not_expected).never
128 lambda {
129 @mock.not_expected
130 }.should raise_error(MockExpectationError, "Mock 'test mock' expected :not_expected with (no args) 0 times, but received it once")
131 end
132
133 it "should raise when told to" do
134 @mock.should_receive(:something).and_raise(RuntimeError)
135 lambda do
136 @mock.something
137 end.should raise_error(RuntimeError)
138 end
139
140 it "should raise passed an Exception instance" do
141 error = RuntimeError.new("error message")
142 @mock.should_receive(:something).and_raise(error)
143 lambda {
144 @mock.something
145 }.should raise_error(RuntimeError, "error message")
146 end
147
148 it "should raise RuntimeError with passed message" do
149 @mock.should_receive(:something).and_raise("error message")
150 lambda {
151 @mock.something
152 }.should raise_error(RuntimeError, "error message")
153 end
154
155 it "should not raise when told to if args dont match" do
156 @mock.should_receive(:something).with(2).and_raise(RuntimeError)
157 lambda {
158 @mock.something 1
159 }.should raise_error(MockExpectationError)
160 end
161
162 it "should throw when told to" do
163 @mock.should_receive(:something).and_throw(:blech)
164 lambda {
165 @mock.something
166 }.should throw_symbol(:blech)
167 end
168
169 it "should raise when explicit return and block constrained" do
170 lambda {
171 @mock.should_receive(:fruit) do |colour|
172 :strawberry
173 end.and_return :apple
174 }.should raise_error(AmbiguousReturnError)
175 end
176
177 it "should ignore args on any args" do
178 @mock.should_receive(:something).at_least(:once).with(any_args)
179 @mock.something
180 @mock.something 1
181 @mock.something "a", 2
182 @mock.something [], {}, "joe", 7
183 @mock.rspec_verify
184 end
185
186 it "should fail on no args if any args received" do
187 @mock.should_receive(:something).with(no_args())
188 lambda {
189 @mock.something 1
190 }.should raise_error(MockExpectationError, "Mock 'test mock' expected :something with (no args) but received it with (1)")
191 end
192
193 it "should fail when args are expected but none are received" do
194 @mock.should_receive(:something).with(1)
195 lambda {
196 @mock.something
197 }.should raise_error(MockExpectationError, "Mock 'test mock' expected :something with (1) but received it with (no args)")
198 end
199
200 it "should return value from block by default" do
201 @mock.stub!(:method_that_yields).and_yield
202 @mock.method_that_yields { :returned_obj }.should == :returned_obj
203 @mock.rspec_verify
204 end
205
206 it "should yield 0 args to blocks that take a variable number of arguments" do
207 @mock.should_receive(:yield_back).with(no_args()).once.and_yield
208 a = nil
209 @mock.yield_back {|*a|}
210 a.should == []
211 @mock.rspec_verify
212 end
213
214 it "should yield 0 args multiple times to blocks that take a variable number of arguments" do
215 @mock.should_receive(:yield_back).once.with(no_args()).once.and_yield.
216 and_yield
217 a = nil
218 b = []
219 @mock.yield_back {|*a| b << a}
220 b.should == [ [], [] ]
221 @mock.rspec_verify
222 end
223
224 it "should yield one arg to blocks that take a variable number of arguments" do
225 @mock.should_receive(:yield_back).with(no_args()).once.and_yield(99)
226 a = nil
227 @mock.yield_back {|*a|}
228 a.should == [99]
229 @mock.rspec_verify
230 end
231
232 it "should yield one arg 3 times consecutively to blocks that take a variable number of arguments" do
233 @mock.should_receive(:yield_back).once.with(no_args()).once.and_yield(99).
234 and_yield(43).
235 and_yield("something fruity")
236 a = nil
237 b = []
238 @mock.yield_back {|*a| b << a}
239 b.should == [[99], [43], ["something fruity"]]
240 @mock.rspec_verify
241 end
242
243 it "should yield many args to blocks that take a variable number of arguments" do
244 @mock.should_receive(:yield_back).with(no_args()).once.and_yield(99, 27, "go")
245 a = nil
246 @mock.yield_back {|*a|}
247 a.should == [99, 27, "go"]
248 @mock.rspec_verify
249 end
250
251 it "should yield many args 3 times consecutively to blocks that take a variable number of arguments" do
252 @mock.should_receive(:yield_back).once.with(no_args()).once.and_yield(99, :green, "go").
253 and_yield("wait", :amber).
254 and_yield("stop", 12, :red)
255 a = nil
256 b = []
257 @mock.yield_back {|*a| b << a}
258 b.should == [[99, :green, "go"], ["wait", :amber], ["stop", 12, :red]]
259 @mock.rspec_verify
260 end
261
262 it "should yield single value" do
263 @mock.should_receive(:yield_back).with(no_args()).once.and_yield(99)
264 a = nil
265 @mock.yield_back {|a|}
266 a.should == 99
267 @mock.rspec_verify
268 end
269
270 it "should yield single value 3 times consecutively" do
271 @mock.should_receive(:yield_back).once.with(no_args()).once.and_yield(99).
272 and_yield(43).
273 and_yield("something fruity")
274 a = nil
275 b = []
276 @mock.yield_back {|a| b << a}
277 b.should == [99, 43, "something fruity"]
278 @mock.rspec_verify
279 end
280
281 it "should yield two values" do
282 @mock.should_receive(:yield_back).with(no_args()).once.and_yield('wha', 'zup')
283 a, b = nil
284 @mock.yield_back {|a,b|}
285 a.should == 'wha'
286 b.should == 'zup'
287 @mock.rspec_verify
288 end
289
290 it "should yield two values 3 times consecutively" do
291 @mock.should_receive(:yield_back).once.with(no_args()).once.and_yield('wha', 'zup').
292 and_yield('not', 'down').
293 and_yield(14, 65)
294 a, b = nil
295 c = []
296 @mock.yield_back {|a,b| c << [a, b]}
297 c.should == [['wha', 'zup'], ['not', 'down'], [14, 65]]
298 @mock.rspec_verify
299 end
300
301 it "should fail when calling yielding method with wrong arity" do
302 @mock.should_receive(:yield_back).with(no_args()).once.and_yield('wha', 'zup')
303 lambda {
304 @mock.yield_back {|a|}
305 }.should raise_error(MockExpectationError, "Mock 'test mock' yielded |\"wha\", \"zup\"| to block with arity of 1")
306 end
307
308 it "should fail when calling yielding method consecutively with wrong arity" do
309 @mock.should_receive(:yield_back).once.with(no_args()).once.and_yield('wha', 'zup').
310 and_yield('down').
311 and_yield(14, 65)
312 lambda {
313 a, b = nil
314 c = []
315 @mock.yield_back {|a,b| c << [a, b]}
316 }.should raise_error(MockExpectationError, "Mock 'test mock' yielded |\"down\"| to block with arity of 2")
317 end
318
319 it "should fail when calling yielding method without block" do
320 @mock.should_receive(:yield_back).with(no_args()).once.and_yield('wha', 'zup')
321 lambda {
322 @mock.yield_back
323 }.should raise_error(MockExpectationError, "Mock 'test mock' asked to yield |[\"wha\", \"zup\"]| but no block was passed")
324 end
325
326 it "should be able to mock send" do
327 @mock.should_receive(:send).with(any_args)
328 @mock.send 'hi'
329 @mock.rspec_verify
330 end
331
332 it "should be able to raise from method calling yielding mock" do
333 @mock.should_receive(:yield_me).and_yield 44
334
335 lambda {
336 @mock.yield_me do |x|
337 raise "Bang"
338 end
339 }.should raise_error(StandardError, "Bang")
340
341 @mock.rspec_verify
342 end
343
344 it "should clear expectations after verify" do
345 @mock.should_receive(:foobar)
346 @mock.foobar
347 @mock.rspec_verify
348 lambda {
349 @mock.foobar
350 }.should raise_error(MockExpectationError, "Mock 'test mock' received unexpected message :foobar with (no args)")
351 end
352
353 it "should restore objects to their original state on rspec_reset" do
354 mock = mock("this is a mock")
355 mock.should_receive(:blah)
356 mock.rspec_reset
357 mock.rspec_verify #should throw if reset didn't work
358 end
359
360 it "should work even after method_missing starts raising NameErrors instead of NoMethodErrors" do
361 # Object#method_missing throws either NameErrors or NoMethodErrors.
362 #
363 # On a fresh ruby program Object#method_missing:
364 # * raises a NoMethodError when called directly
365 # * raises a NameError when called indirectly
366 #
367 # Once Object#method_missing has been called at least once (on any object)
368 # it starts behaving differently:
369 # * raises a NameError when called directly
370 # * raises a NameError when called indirectly
371 #
372 # There was a bug in Mock#method_missing that relied on the fact
373 # that calling Object#method_missing directly raises a NoMethodError.
374 # This example tests that the bug doesn't exist anymore.
375
376
377 # Ensures that method_missing always raises NameErrors.
378 a_method_that_doesnt_exist rescue
379
380
381 @mock.should_receive(:foobar)
382 @mock.foobar
383 @mock.rspec_verify
384
385 lambda { @mock.foobar }.should_not raise_error(NameError)
386 lambda { @mock.foobar }.should raise_error(MockExpectationError)
387 end
388
389 it "should temporarily replace a method stub on a mock" do
390 @mock.stub!(:msg).and_return(:stub_value)
391 @mock.should_receive(:msg).with(:arg).and_return(:mock_value)
392 @mock.msg(:arg).should equal(:mock_value)
393 @mock.msg.should equal(:stub_value)
394 @mock.msg.should equal(:stub_value)
395 @mock.rspec_verify
396 end
397
398 it "should temporarily replace a method stub on a non-mock" do
399 non_mock = Object.new
400 non_mock.stub!(:msg).and_return(:stub_value)
401 non_mock.should_receive(:msg).with(:arg).and_return(:mock_value)
402 non_mock.msg(:arg).should equal(:mock_value)
403 non_mock.msg.should equal(:stub_value)
404 non_mock.msg.should equal(:stub_value)
405 non_mock.rspec_verify
406 end
407
408 it "should assign stub return values" do
409 mock = Mock.new('name', :message => :response)
410 mock.message.should == :response
411 end
412
413 end
414
415 describe "a mock message receiving a block" do
416 before(:each) do
417 @mock = mock("mock")
418 @calls = 0
419 end
420
421 def add_call
422 @calls = @calls + 1
423 end
424
425 it "should call the block after #should_receive" do
426 @mock.should_receive(:foo) { add_call }
427
428 @mock.foo
429
430 @calls.should == 1
431 end
432
433 it "should call the block after #once" do
434 @mock.should_receive(:foo).once { add_call }
435
436 @mock.foo
437
438 @calls.should == 1
439 end
440
441 it "should call the block after #twice" do
442 @mock.should_receive(:foo).twice { add_call }
443
444 @mock.foo
445 @mock.foo
446
447 @calls.should == 2
448 end
449
450 it "should call the block after #times" do
451 @mock.should_receive(:foo).exactly(10).times { add_call }
452
453 (1..10).each { @mock.foo }
454
455 @calls.should == 10