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