Best practice for model callbacks?


#1

In many of my models, I have callback methods like this:

class MyModel < ActiveRecord::Base

before_save :do_something

def do_something
some code here…
end

end

The do_something method is a public method that is sometimes called on
its
own, and also called whenever the model is saved. Let’s say there are
six
specs that are required to fully test the do_something method. What is
considered best practice for how the before_save filter should be
tested?
If I say that I’m only ever going to test the behavior, it means that I
need
to basically rewrite those six specs to make sure they hold whenever the
model is saved, as well as when the do_something method is called
explicitly. I don’t like having to repeat myself this way, particularly
considering that a model may have multiple callbacks like this so I end
up
having to repeat myself a lot. The alternative is to just do something
like:

x = MyModel.new
x.should_receive(:do_something)
x.save

But of course this tests implementation rather than behavior which is
usually not desirable. But in this situation I’m tending to prefer it
over
having to do a ton of rewriting of specs. What are others’ thoughts on
this?

Thanks…


#2

Oh, and I suppose the third option here could be to so something like:

[:do_something, :save].each do |method_name|
it “should satisfy some spec when we call the #{method_name} method” do
x = MyModel.new
x.call(method_name)
x.should … (whatever the condition is here)
end
end

I use this sort of technique at time to keep my specs dry, simple and
behavior-driven at the same time, but I find it can make the spec files
a
bit hard to read through so I try not to use it unless it is really
needed…


#3

In cases like this I write tests for the method, in your case
do_something,
and then spec the behavior that a filter exists which calls that method.
No
more, no less. You can safely assume that ActiveRecord itself has tests
to
ensure a properly declared before filter will be called when the model
is
saved.

HTH,
Mike

On Apr 16, 2009 1:34 PM, “Barun S.” removed_email_address@domain.invalid wrote:

In many of my models, I have callback methods like this:

class MyModel < ActiveRecord::Base

before_save :do_something

def do_something
some code here…
end

end

The do_something method is a public method that is sometimes called on
its
own, and also called whenever the model is saved. Let’s say there are
six
specs that are required to fully test the do_something method. What is
considered best practice for how the before_save filter should be
tested?
If I say that I’m only ever going to test the behavior, it means that I
need
to basically rewrite those six specs to make sure they hold whenever the
model is saved, as well as when the do_something method is called
explicitly. I don’t like having to repeat myself this way, particularly
considering that a model may have multiple callbacks like this so I end
up
having to repeat myself a lot. The alternative is to just do something
like:

x = MyModel.new
x.should_receive(:do_something)
x.save

But of course this tests implementation rather than behavior which is
usually not desirable. But in this situation I’m tending to prefer it
over
having to do a ton of rewriting of specs. What are others’ thoughts on
this?

Thanks…


#4

What is the thing that’s being done in a callback and also sometimes
called by clients? Usually the semantics are different and you don’t
want to treat them exactly the same…

At any rate, you can be creative with shared example groups to get rid
of the duplication. Something like

describe “do_something”, :shared => true do
it “should update the posts_count” do
lambda { do_action }.
should change(subject, :posts_count).by(1)
end

it “should send an email” do
do_action
# however you get emails…I forget
end
end

describe Foo, “when saved” do
it_should_behave_like “do_something”

subject { new_foo }

def do_action
subject.save!
end
end

describe Foo, “when do_something is called” do
it_should_behave_like “do_something”

subject { new_foo }

def do_action
subject.do_something
end
end

Does that help?

Pat


#5

Errr… before callback. I’ve been spending too much time with
controllers.
:slight_smile:

On Apr 16, 2009 1:34 PM, “Barun S.” removed_email_address@domain.invalid wrote:

In many of my models, I have callback methods like this:

class MyModel < ActiveRecord::Base

before_save :do_something

def do_something
some code here…
end

end

The do_something method is a public method that is sometimes called on
its
own, and also called whenever the model is saved. Let’s say there are
six
specs that are required to fully test the do_something method. What is
considered best practice for how the before_save filter should be
tested?
If I say that I’m only ever going to test the behavior, it means that I
need
to basically rewrite those six specs to make sure they hold whenever the
model is saved, as well as when the do_something method is called
explicitly. I don’t like having to repeat myself this way, particularly
considering that a model may have multiple callbacks like this so I end
up
having to repeat myself a lot. The alternative is to just do something
like:

x = MyModel.new
x.should_receive(:do_something)
x.save

But of course this tests implementation rather than behavior which is
usually not desirable. But in this situation I’m tending to prefer it
over
having to do a ton of rewriting of specs. What are others’ thoughts on
this?

Thanks…


#6

Yes that does help, thanks! I didn’t know about shared example groups.