Set expectation using self in constructor?

I find myself using this pattern quite a bit.

rspec 1.30
ruby 1.9.1, 1.9.2-rc2, jruby 1.51 all on osx 10.6.4

class Foo
def initialize
@bar = Bar.new
end
end

context “init” do
it “should allocate a helper class Bar” do
Bar.should_receive(:new)
Foo.new
end
end

That all works well and as expected. Where I get stuck is when I change
the signature for Bar to accept an argument from Foo like so:

class Foo
def initialize
@bar = Bar.new self
end
end

try 1

context “init” do
it “should allocate a helper class Bar” do
Bar.should_receive(:new).with(self) # self refers to rspec here
Foo.new
end
end

try 2

context “init” do
let(:foo) { Foo.new }

it “should allocate a helper class Bar” do
Bar.should_receive(:new).with(foo) # foo is a different instance
Foo.new
end
end

try 3

context “init” do
it “should allocate a helper class Bar” do
Bar.should_receive(:new).with(instance_of(Foo)) # works but seems
wrong
Foo.new
end
end

I have tried lots of techniques for setting an argument expectation in
my spec, but none of them work completely. How do others solve this? Or
have I discovered a spec anti-pattern?

If this is an anti-pattern, what is the suggested programming technique
to avoid it?

cr

On Wed, Jul 14, 2010 at 10:26 AM, Chuck R. [email protected]
wrote:

def initialize
end

If this is an anti-pattern, what is the suggested programming technique to avoid it?
The problem is that the instance of Foo that you are testing for
doesn’t exist until you call Foo.new.

I’d change this to spec the results rather than the implementation:

e.g.

foo = Foo.new
foo.bar.should == foo

Assuming that foo and bar have public accessors for bar and foo
respectively.

If not you can use instance_variable_get to ‘get’ around that.

HTH


Rick DeNatale

Blog: http://talklikeaduck.denhaven2.com/
Github: rubyredrick (Rick DeNatale) · GitHub
Twitter: @RickDeNatale
WWR: http://www.workingwithrails.com/person/9021-rick-denatale
LinkedIn: http://www.linkedin.com/in/rickdenatale

On 14 Jul 2010, at 15:26, Chuck R. wrote:

def initialize
end

If this is an anti-pattern, what is the suggested programming technique to avoid it?
You can do this, by using a test spy to remember the value of foo passed
into the stubbed constructor and then later comparing it:

let(:foo) { Foo.new }

it “should allocate a helper class Foo” do
actual_foo = Bar.should_receive(:new) do |the_foo|
the_foo
end
actual_foo.should == foo
end

Whether you want to do this though, is another question. I think it’s a
bit of an anti-pattern personally. I’d probably let acceptance tests
catch mistakes in this kind of thing, and concentrate on speccing the
interaction between Foo and Bar once you’ve got the instances spun up.

cr


rspec-users mailing list
[email protected]
http://rubyforge.org/mailman/listinfo/rspec-users

cheers,
Matt

http://blog.mattwynne.net
+44(0)7974 430184

On Jul 14, 2010, at 4:20 PM, Matt W. wrote:

end

Whether you want to do this though, is another question. I think it’s a bit of an anti-pattern personally. I’d probably let acceptance tests catch mistakes in this kind of thing, and concentrate on speccing the interaction between Foo and Bar once you’ve got the instances spun up.

For those following along at home, this exact technique did not work.
The +actual_foo+ variable was holding some mock value instead of the
real self value.

I fixed it by assigning to a variable inside the block that had been
defined outside the block (avoiding block scope issues).

let(:foo) { Foo.new }

it “should allocate a helper class Foo” do
actual_foo = nil
Bar.should_receive(:new) do |the_foo|
actual_foo = the_foo
end

actual_foo.should == foo
end

This succeeds.

Thanks to all for your help.

cr

On Jul 14, 2010, at 4:20 PM, Matt W. wrote:

end

Whether you want to do this though, is another question. I think it’s a bit of an anti-pattern personally. I’d probably let acceptance tests catch mistakes in this kind of thing, and concentrate on speccing the interaction between Foo and Bar once you’ve got the instances spun up.

This is an interesting technique. I didn’t realize that using the block
form of expectations/matchers returned a value. Thanks for the tip!

cr

On 15 Jul 2010, at 14:55, Chuck R. wrote:

the_foo
end
actual_foo.should == foo
end

Whether you want to do this though, is another question. I think it’s a bit of an anti-pattern personally. I’d probably let acceptance tests catch mistakes in this kind of thing, and concentrate on speccing the interaction between Foo and Bar once you’ve got the instances spun up.

For those following along at home, this exact technique did not work. The +actual_foo+ variable was holding some mock value instead of the real self value.

Sorry. Do we think this is a bug in rspec? I’d have expected the block
to return the last evaluated value. But is that just me?

rspec-users mailing list
[email protected]
http://rubyforge.org/mailman/listinfo/rspec-users

cheers,
Matt

http://blog.mattwynne.net
+44(0)7974 430184

On 16 Jul 2010, at 10:29, Matt W. wrote:

For those following along at home, this exact technique did not work. The +actual_foo+ variable was holding some mock value instead of the real self value.
Sorry. Do we think this is a bug in rspec? I’d have expected the block to return the last evaluated value. But is that just me?

It doesn’t look like a bug to me – I expect #should_receive to return a
message expectation, e.g. so that I can call #with/#and_return on it,
and it would seem weird for it to behave otherwise when a block is
supplied.

Cheers,
-Tom

On Jul 16, 2010, at 4:45 AM, Tom S. wrote:

On 16 Jul 2010, at 10:29, Matt W. wrote:

For those following along at home, this exact technique did not work. The +actual_foo+ variable was holding some mock value instead of the real self value.
Sorry. Do we think this is a bug in rspec? I’d have expected the block to return the last evaluated value. But is that just me?

It doesn’t look like a bug to me – I expect #should_receive to return a message expectation, e.g. so that I can call #with/#and_return on it, and it would seem weird for it to behave otherwise when a block is supplied.

Correct. The block syntax is an alternative to and_returns, and_yields,
and_raises, etc. The block is evaluated lazily, when the stubbed or
mocked method is invoked.

HTH,
David

On 16 Jul 2010, at 10:45, Tom S. wrote:

On 16 Jul 2010, at 10:29, Matt W. wrote:

For those following along at home, this exact technique did not work. The +actual_foo+ variable was holding some mock value instead of the real self value.
Sorry. Do we think this is a bug in rspec? I’d have expected the block to return the last evaluated value. But is that just me?

It doesn’t look like a bug to me – I expect #should_receive to return a message expectation, e.g. so that I can call #with/#and_return on it, and it would seem weird for it to behave otherwise when a block is supplied.

Cheers,
-Tom

Of course, silly me.


rspec-users mailing list
[email protected]
http://rubyforge.org/mailman/listinfo/rspec-users

cheers,
Matt

http://blog.mattwynne.net
+44(0)7974 430184