2

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!

DJ Gruby
  • 159
  • 1
  • 2
  • 11

2 Answers2

1

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
Patrick Oscity
  • 53,604
  • 17
  • 144
  • 168
  • Nope, it doesn't work. The following `NameError` is reported: `undefined local variable or method 'objekt' for #`. – DJ Gruby Nov 03 '14 at 13:44
  • Sorry please check again – Patrick Oscity Nov 03 '14 at 13:46
  • Nope, sorry, still no change. Getting the same error message as before: `Double "OtherKlass" received unexpected message :closed? with (no args)`. – DJ Gruby Nov 03 '14 at 15:06
  • Here's what helped me. Setting class variable explicitly before each test solves the problem: `before(:each) { MyKlass.class_variable_set :@@klass_var, nil }`. – DJ Gruby Nov 03 '14 at 15:11
0

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.

DJ Gruby
  • 159
  • 1
  • 2
  • 11