Stubbing when an object constructor creates another object

So, I have a code that is very simplified, looks like this:

class B
  def initialize opts
    @opts = opts
  end
end

class A
  def initialize opts
    # defaults etc applied to opts
    @b = B.new opts
  end
end

In other words, when I initialize A with parameters, it creates B and passes it a modified set of parameters.

I would like to verify that B.new is getting the right arguments. Right now, I'm doing it this way using RSpec / RR:

@b = Object.new
# stub methods on @b here
stub(B).new { |options|
  options[:foo].should == 'whatever'
  @b
}
A.new({:foo => 'whatever'})

But this has two problems.

Firstly, I cannot create a real copy Bwith actual parameters. If I call B.new inside the block, it invokes the plastered version and the loop until the stack appears. I can set @b = B.newbefore starting, but I still don't know the parameters that will be passed, defeating the test point.

( , - : , unit test A B, , , , .)

-, should , it ... do ... end. B (. ), .

?

+5
3

- B.should_receive(:new).with({:foo => 'whatever'}).

stubbing/mocking ; , B , , .

+3

should Marc-André Lafortune, , RSpec 3. expect :

expect(B).to receive(:new).with(foo: 'whatever')

: , B.new (, ), and_return:

b = instance_double(B)
expect(B).to receive(:new).with(foo: 'whatever').and_return(b)
+8

RR version of Mark-Andre's answer:

before do
  stub(B).new { @b }
end

it 'uses the correct options' do
  B.should have_received.new(hash_including(:foo => 'whatever'))
end
+1
source

All Articles