Stubbing @instance.association.build

Hi all,

I am trying to spec a controller for a nested resource:

Running the spec as it is in the gist results in

undefined method `save’ for nil:NilClass (line 66 in the gist)

So should_receive is interfering with the build message resulting in
@course ending up nil.

Is there a way to stub “build” so that the assertion works and does
not result in @course == nil?

Many thanks in advance,
Nickolay

On Wed, Feb 17, 2010 at 5:44 AM, Nickolay K. [email protected]
wrote:

So should_receive is interfering with the build message resulting in
@course ending up nil.

Is there a way to stub “build” so that the assertion works and does
not result in @course == nil?

Many thanks in advance,
Nickolay

I don’t see @new_course getting defined anywhere. Try assigning it a
non-nil value in each of the POST examples (or in before(:each) in
that group).

I don’t see @new_course getting defined anywhere. Try assigning it a
non-nil value in each of the POST examples (or in before(:each) in
that group).

Thanks, David!

Am I right in assuming that I have to check that @new_course received
a “save” and returned true in the same it-block?

This works:

it “should build the new course” do

@teacher.courses.should_receive(:build).with(@valid_course_attributes).and_return(@new_course)
@new_course.should_receive(:save).and_return(true)
do_post
end

This does not (naturally):

it “should build the new course” do

@teacher.courses.should_receive(:build).with(@valid_course_attributes).and_return(@new_course)
do_post
end

it “should build the new course” do
@new_course.should_receive(:save).and_return(true)
do_post
end

Is there a way to propagate the @new_course instance variable to the
next it-block?

Best,
Nickolay

On Wed, Feb 17, 2010 at 8:03 AM, Nickolay K. [email protected]
wrote:

it “should build the new course” do

@teacher.courses.should_receive(:build).with(@valid_course_attributes).and_return(@new_course)
@new_course.should_receive(:save).and_return(true)
do_post
end

This is not working for the reason that I think you think it’s
working. and_return is not an expectation - it is a command telling
@teacher to return @new_course when it receives :build. You have to
define @new_course in the spec. The reason this is working in this
case is that @new_course == nil, so and_return(@new_course) is
returning nil and then @new_course.should_receive(:save) is telling
nil to expect :save.

do_post
end

Is there a way to propagate the @new_course instance variable to the
next it-block?

Nope. But you can define @new_course before(:each) example:

before(:each) { @new_course = stub_model(Course) }

Then it will be non-nil and all should be well.

That all make sense?

David

On Wed, Feb 17, 2010 at 8:31 AM, Nickolay K. [email protected]
wrote:

Machinist.

What is the scope of instance variables defined in a before(:each)
block? They are available to all it-blocks, yet changes made to an
instance variable in one it-block are reverted before the next one,
correct?

Close, but not exactly. Each example is run in its own world. Any
before(:each) blocks are run before each example in the same world, so
the instance variables are not shared in any way at all from example
to example. So the following will pass if examples are run in any
order:

before(:each) { @foo = 1 }
it(“does something”) { @foo +=1; @foo.should == 2}
it(“does something else”) { @foo.should == 1 }

You can run a before block only once by using before(:all), but that
leads to all sorts of problems related to state-sharing across
examples and should generally be avoided.

HTH,
David

This is not working for the reason that I think you think it’s
working. and_return is not an expectation - it is a command telling
@teacher to return @new_course when it receives :build. You have to
define @new_course in the spec.

I did the following:

and it works as expected. make_unsaved is a class method added by
Machinist.

What is the scope of instance variables defined in a before(:each)
block? They are available to all it-blocks, yet changes made to an
instance variable in one it-block are reverted before the next one,
correct?

Best,
Nickolay

Thanks for the explanation, David!

Makes sense now.

Best,
Nickolay