File: stub_spec.rb

package info (click to toggle)
ruby-rspec-mocks 2.14.5-1
  • links: PTS, VCS
  • area: main
  • in suites: jessie, jessie-kfreebsd
  • size: 868 kB
  • ctags: 725
  • sloc: ruby: 8,227; makefile: 4
file content (353 lines) | stat: -rw-r--r-- 11,366 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
require 'spec_helper'

module RSpec
  module Mocks
    describe "A method stub" do
      before(:each) do
        @class = Class.new do
          class << self
            def existing_class_method
              existing_private_class_method
            end

            private
            def existing_private_class_method
              :original_value
            end
          end

          def existing_instance_method
            existing_private_instance_method
          end

          private
          def existing_private_instance_method
            :original_value
          end
        end
        @instance = @class.new
        @stub = Object.new
      end

      describe "using stub" do
        it "returns declared value when message is received" do
          @instance.stub(:msg).and_return(:return_value)
          expect(@instance.msg).to equal(:return_value)
          verify @instance
        end
      end

      describe "using stub!" do
        before do
          allow(RSpec).to receive(:deprecate)
        end

        it "warns of deprecation" do
          expect(RSpec).to receive(:deprecate).with("stub!", :replacement => "stub")
          @instance.stub!(:msg).and_return(:return_value)
        end

        it "returns the declared value when the message is received" do
          @instance.stub!(:msg).and_return(:return_value)
          expect(@instance.msg).to equal(:return_value)
          verify @instance
        end

        it "can be used to stub the example context itself (since `stub` returns a test dobule instead)" do
          stub!(:foo).and_return(5)
          expect(foo).to eq(5)
        end
      end

      describe 'using unstub' do
        it 'removes the message stub' do
          @instance.stub(:msg)
          @instance.unstub(:msg)
          expect { @instance.msg }.to raise_error NoMethodError
        end
      end

      describe 'using unstub!' do
        it 'removes the message stub but warns about deprecation' do
          @instance.stub(:msg)
          RSpec.should_receive(:deprecate).with("unstub!", :replacement => "unstub")
          @instance.unstub!(:msg)
          expect { @instance.msg }.to raise_error NoMethodError
        end
      end

      it "instructs an instance to respond_to the message" do
        @instance.stub(:msg)
        expect(@instance).to respond_to(:msg)
      end

      it "instructs a class object to respond_to the message" do
        @class.stub(:msg)
        expect(@class).to respond_to(:msg)
      end

      it "ignores when expected message is received with no args" do
        @instance.stub(:msg)
        @instance.msg
        expect do
          verify @instance
        end.not_to raise_error
      end

      it "ignores when message is received with args" do
        @instance.stub(:msg)
        @instance.msg(:an_arg)
        expect do
          verify @instance
        end.not_to raise_error
      end

      it "ignores when expected message is not received" do
        @instance.stub(:msg)
        expect do
          verify @instance
        end.not_to raise_error
      end

      it "handles multiple stubbed methods" do
        @instance.stub(:msg1 => 1, :msg2 => 2)
        expect(@instance.msg1).to eq(1)
        expect(@instance.msg2).to eq(2)
      end

      describe "#rspec_reset" do
        it "removes stubbed methods that didn't exist" do
          @instance.stub(:non_existent_method)
          reset @instance
          expect(@instance).not_to respond_to(:non_existent_method)
        end

        it "restores existing instance methods" do
          # See bug reports 8302 adn 7805
          @instance.stub(:existing_instance_method) { :stub_value }
          reset @instance
          expect(@instance.existing_instance_method).to eq(:original_value)
        end

        it "restores existing private instance methods" do
          # See bug reports 8302 adn 7805
          @instance.stub(:existing_private_instance_method) { :stub_value }
          reset @instance
          expect(@instance.send(:existing_private_instance_method)).to eq(:original_value)
        end

        it "restores existing class methods" do
          # See bug reports 8302 adn 7805
          @class.stub(:existing_class_method) { :stub_value }
          reset @class
          expect(@class.existing_class_method).to eq(:original_value)
        end

        it "restores existing private class methods" do
          # See bug reports 8302 adn 7805
          @class.stub(:existing_private_class_method) { :stub_value }
          reset @class
          expect(@class.send(:existing_private_class_method)).to eq(:original_value)
        end

        it "does not remove existing methods that have been stubbed twice" do
          @instance.stub(:existing_instance_method)
          @instance.stub(:existing_instance_method)

          reset @instance

          expect(@instance.existing_instance_method).to eq(:original_value)
        end

        it "correctly restores the visibility of methods whose visibility has been tweaked on the singleton class" do
          # hello is a private method when mixed in, but public on the module
          # itself
          mod = Module.new {
            extend self
            def hello; :hello; end

            private :hello
            class << self; public :hello; end;
          }

          expect(mod.hello).to eq(:hello)

          mod.stub(:hello) { :stub }
          reset mod

          expect(mod.hello).to eq(:hello)
        end

        if RUBY_VERSION >= '2.0.0'
          context "with a prepended module (ruby 2.0.0+)" do
            before do
              mod = Module.new do
                def existing_instance_method
                  "#{super}_prepended".to_sym
                end
              end

              @prepended_class = Class.new(@class) do
                prepend mod

                def non_prepended_method
                  :not_prepended
                end
              end
              @prepended_instance = @prepended_class.new
            end

            it "restores prepended instance methods" do
              allow(@prepended_instance).to receive(:existing_instance_method) { :stubbed }
              expect(@prepended_instance.existing_instance_method).to eq :stubbed

              reset @prepended_instance
              expect(@prepended_instance.existing_instance_method).to eq :original_value_prepended
            end

            it "restores non-prepended instance methods" do
              allow(@prepended_instance).to receive(:non_prepended_method) { :stubbed }
              expect(@prepended_instance.non_prepended_method).to eq :stubbed

              reset @prepended_instance
              expect(@prepended_instance.non_prepended_method).to eq :not_prepended
            end
          end
        end
      end

      it "returns values in order to consecutive calls" do
        @instance.stub(:msg).and_return("1",2,:three)
        expect(@instance.msg).to eq("1")
        expect(@instance.msg).to eq(2)
        expect(@instance.msg).to eq(:three)
      end

      it "keeps returning last value in consecutive calls" do
        @instance.stub(:msg).and_return("1",2,:three)
        expect(@instance.msg).to eq("1")
        expect(@instance.msg).to eq(2)
        expect(@instance.msg).to eq(:three)
        expect(@instance.msg).to eq(:three)
        expect(@instance.msg).to eq(:three)
      end

      it "yields a specified object" do
        @instance.stub(:method_that_yields).and_yield(:yielded_obj)
        current_value = :value_before
        @instance.method_that_yields {|val| current_value = val}
        expect(current_value).to eq :yielded_obj
        verify @instance
      end

      it "yields multiple times with multiple calls to and_yield" do
        @instance.stub(:method_that_yields_multiple_times).and_yield(:yielded_value).
                                                       and_yield(:another_value)
        current_value = []
        @instance.method_that_yields_multiple_times {|val| current_value << val}
        expect(current_value).to eq [:yielded_value, :another_value]
        verify @instance
      end

      it "yields a specified object and return another specified object" do
        yielded_obj = double("my mock")
        yielded_obj.should_receive(:foo).with(:bar)
        @instance.stub(:method_that_yields_and_returns).and_yield(yielded_obj).and_return(:baz)
        expect(@instance.method_that_yields_and_returns { |o| o.foo :bar }).to eq :baz
      end

      it "throws when told to" do
        @stub.stub(:something).and_throw(:up)
        expect { @stub.something }.to throw_symbol(:up)
      end

      it "throws with argument when told to" do
        @stub.stub(:something).and_throw(:up, 'high')
        expect { @stub.something }.to throw_symbol(:up, 'high')
      end

      it "overrides a pre-existing method" do
        @stub.stub(:existing_instance_method).and_return(:updated_stub_value)
        expect(@stub.existing_instance_method).to eq :updated_stub_value
      end

      it "overrides a pre-existing stub" do
        @stub.stub(:foo) { 'bar' }
        @stub.stub(:foo) { 'baz' }
        expect(@stub.foo).to eq 'baz'
      end

      it "allows a stub and an expectation" do
        @stub.stub(:foo).with("bar")
        @stub.should_receive(:foo).with("baz")
        @stub.foo("bar")
        @stub.foo("baz")
      end

      it "calculates return value by executing block passed to #and_return" do
        @stub.stub(:something).with("a","b","c").and_return { |a,b,c| c+b+a }
        expect(@stub.something("a","b","c")).to eq "cba"
        verify @stub
      end
    end

    describe "A method stub with args" do
      before(:each) do
        @stub = Object.new
        @stub.stub(:foo).with("bar")
      end

      it "does not complain if not called" do
      end

      it "does not complain if called with arg" do
        @stub.foo("bar")
      end

      it "complains if called with no arg" do
        expect {
          @stub.foo
        }.to raise_error(/received :foo with unexpected arguments/)
      end

      it "complains if called with other arg", :github_issue => [123,147] do
        expect {
          @stub.foo("other")
        }.to raise_error(/received :foo with unexpected arguments.*Please stub a default value/m)
      end

      it "does not complain if also mocked w/ different args" do
        @stub.should_receive(:foo).with("baz")
        @stub.foo("bar")
        @stub.foo("baz")
      end

      it "complains if also mocked w/ different args AND called w/ a 3rd set of args" do
        @stub.should_receive(:foo).with("baz")
        @stub.foo("bar")
        @stub.foo("baz")
        expect {
          @stub.foo("other")
        }.to raise_error
      end

      it "supports options" do
        @stub.stub(:foo, :expected_from => "bar")
      end

      it 'uses the correct stubbed response when responding to a mock expectation' do
        @stub.stub(:bar) { 15 }
        @stub.stub(:bar).with(:eighteen) { 18 }
        @stub.stub(:bar).with(:thirteen) { 13 }

        @stub.should_receive(:bar).exactly(4).times

        expect(@stub.bar(:blah)).to eq(15)
        expect(@stub.bar(:thirteen)).to eq(13)
        expect(@stub.bar(:eighteen)).to eq(18)
        expect(@stub.bar).to eq(15)
      end
    end

  end
end