Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
183 views
in Technique[技术] by (71.8m points)

ruby on rails - How to test model's callback method independently?

I had a method in a model:

class Article < ActiveRecord::Base
  def do_something
  end
end

I also had a unit test for this method:

# spec/models/article_spec.rb
describe "#do_something" do
  @article = FactoryGirl.create(:article)
  it "should work as expected" do
    @article.do_something
    expect(@article).to have_something
  end
  # ...several other examples for different cases
end

Everything was fine until I found it's better to move this method into a after_save callback:

class Article < ActiveRecord::Base
  after_save :do_something

  def do_something
  end
end

Now all my tests about this method broken. I have to fix it by:

  • No more specific call to do_something because create or save will trigger this method as well, or I'll meet duplicate db actions.
  • Change create to build
  • Test respond_to
  • Use general model.save instead of individual method call model.do_something

    describe "#do_something" do
      @article = FactoryGirl.build(:article)
      it "should work as expected" do
        expect{@article.save}.not_to raise_error
        expect(@article).to have_something
        expect(@article).to respond_to(:do_something)
      end
    end
    

The test passed but my concern is it's no longer about the specific method. The effect will be mixed with other callbacks if more added.

My question is, is there any beautiful way to test model's instance methods independently that becoming a callback?

question from:https://stackoverflow.com/questions/16677718/how-to-test-models-callback-method-independently

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

Callback and Callback behavior are independent tests. If you want to check an after_save callback, you need to think of it as two things:

  1. Is the callback being fired for the right events?
  2. Is the called function doing the right thing?

Assume you have the Article class with many callbacks, this is how you would test:

class Article < ActiveRecord::Base
  after_save    :do_something
  after_destroy :do_something_else
  ...
end

it "triggers do_something on save" do
  expect(@article).to receive(:do_something)
  @article.save
end

it "triggers do_something_else on destroy" do
  expect(@article).to receive(:do_something_else)
  @article.destroy
end

it "#do_something should work as expected" do
  # Actual tests for do_something method
end

This decouples your callbacks from behavior. For example, you could trigger the same callback method article.do_something when some other related object is updated, say like user.before_save { user.article.do_something }. This will accomodate all those.

So, keep testing your methods as usual. Worry about the callbacks separately.

Edit: typos and potential misconceptions Edit: change "do something" to "trigger something"


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...