6

I have an object MyObject:

class MyObject

  def initialize(options = {})
    @stat_to_load = options[:stat_to_load] || 'test'
  end

  def results
   []
  end
end

I want to stub the results method only if stat_to_load = "times". How can I do that? I tried:

MyObject.any_instance.stubs(:initialize).with({
  :stat_to_load => "times"
}).stubs(:results).returns(["klala"])

but it does not work. Any idea?

Vega
  • 27,856
  • 27
  • 95
  • 103
Sebastien
  • 6,640
  • 14
  • 57
  • 105
  • 1
    I can see a mismatch on `result` versus `results` in the question. Probably not your answer, but worth fixing? – Neil Slater May 29 '13 at 14:38
  • Oups, copy/paste error – Sebastien May 29 '13 at 14:46
  • I don't even know if this is possible, but probably the right solution is to inject the object or the class, then you have a lot more control over it. Difficult to say / give examples without seeing how this code is being used. – Joshua Cheek May 29 '13 at 14:52
  • How do you code it if you have my class MyObject. I want to stubs for rails tests. – Sebastien May 29 '13 at 14:54

3 Answers3

0

So, I think there is probably a simpler way to test what you're trying to test, but without more context I don't know what to recommend. However, here is some proof-of-concept code to show that what you want to do can be done:

describe "test" do
  class TestClass
    attr_accessor :opts
    def initialize(opts={})
      @opts = opts
    end

    def bar
      []
    end
  end
  let!(:stubbed) do
    TestClass.new(args).tap{|obj| obj.stub(:bar).and_return("bar")}
  end
  let!(:unstubbed) { TestClass.new(args) }

  before :each do
    TestClass.stub(:new) do |args|
      case args
      when { :foo => "foo" }
        stubbed
      else
        unstubbed
      end
    end
  end

  subject { TestClass.new(args) }

  context "special arguments" do
    let(:args) { { :foo => "foo" } }
    its(:bar) { should eq "bar" }
    its(:opts) { should eq({ :foo => "foo" }) }
  end

  context "no special arguments" do
    let(:args) { { :baz => "baz" } }
    its(:bar) { should eq [] }
    its(:opts) { should eq({ :baz => "baz" }) }
  end

end

test
  special arguments
    bar
      should == bar
    opts
      should == {:foo=>"foo"}
  no special arguments
    bar
      should == []
    opts
      should == {:baz=>"baz"}

Finished in 0.01117 seconds
4 examples, 0 failures

However I'm making a lot of use of special subject/let context blocks here. See http://benscheirman.com/2011/05/dry-up-your-rspec-files-with-subject-let-blocks/ for more on that subject.

gregates
  • 6,607
  • 1
  • 31
  • 31
0

Try out below, this should work as expected:

Here, Basically we are actually stubbing new instance getting created and also stubbing results method of the instance which is getting returned.

options = {:stat_to_load =>  "times"}
MyObject.stubs(:new).with(options)
                    .returns(MyObject.new(options).stubs(:results).return(["klala"]))
Sandip Ransing
  • 7,583
  • 4
  • 37
  • 48
0

You could use plain old Ruby inside your test to achieve this.

MyObject.class_eval do
  alias_method :original_results, :results
  define_method(:results?) do
    if stats_to_load == "times"
      ["klala"]
    else
      original_results
    end
  end
end
sank
  • 1
  • 1
  • 1