DJ Gruby
DJ Gruby

Reputation: 179

Double received unexpected message despite of stubbing

Double received unexpected message failure/error is reported when attempting to run the following spec:

MyKlass
  does something
  does something again (FAILED - 1)

Failures:

  1) MyKlass does something again
     Failure/Error: MyKlass.do_something
       Double "OtherKlass" received unexpected message :closed? with (no args)
     # ./lib/my_klass.rb:5:in `do_something'
     # ./spec/my_klass_spec.rb:17:in `block (2 levels) in <top (required)>'

Finished in 2.05 seconds
2 examples, 1 failure

Failed examples:

rspec ./spec/my_klass_spec.rb:16 # MyKlass does something again

Here is a minimal example to easily reproduce this issue...

Spec file spec/my_klass_spec.rb:

 1 require "spec_helper"
 2
 3 class OtherKlass; end
 4 
 5 describe MyKlass do
 6   let(:objekt) { double("OtherKlass", closed?: "NOT REALLY") }
 7 
 8   before :each do
 9     OtherKlass.stub(:get_objekt).and_return(objekt)
10   end
11 
12   it "does something" do
13     MyKlass.do_something
14   end
15 
16   it "does something again" do
17     MyKlass.do_something
18     MyKlass.do_something
19   end
20 end

And code lib/my_klass.rb:

1 class MyKlass
2   @@klass_var = nil
3 
4   def self.do_something
5     if @@klass_var.blank? || @@klass_var.closed?
6       @@klass_var ||= OtherKlass.get_objekt
7     end
8   end
9 end

I cannot understand why closed? is reported to be an unexpected message, when it is stubbed in my spec file on line 6.

Many thanks in advance for your assistance!

Upvotes: 2

Views: 10591

Answers (2)

DJ Gruby
DJ Gruby

Reputation: 179

Setting a class variable explicitly before each test solves the problem:

before(:each) do
  MyKlass.class_variable_set :@@klass_var, nil
end

Probably somebody can find a better solution, however this one has worked for me.

Upvotes: 0

Patrick Oscity
Patrick Oscity

Reputation: 54684

In RSpec 3, you can use class_double, which allows you to create a double of a class. Combined with as_stubbed_const, you can replace the original implementation of a class:

RSpec.describe MyKlass do
  let(:objekt) do
    double(OtherKlass, closed?: 'NOT REALLY')
  end

  before do
    class_double(OtherKlass, get_objekt: objekt).as_stubbed_const
  end

  it 'does something' do
    MyKlass.do_something
  end
end

In Rspec 2 the following should work:

RSpec.describe MyKlass do
  let(:objekt) do
    double('OtherKlass', closed?: 'NOT REALLY')
  end

  before do
    fake_klass = Class.new
    fake_klass.stub(:get_objekt) { objekt }
    stub_const('OtherKlass', fake_klass)
  end

  it 'does something' do
    MyKlass.do_something
  end
end

Upvotes: 1

Related Questions