如何独立测试模型的回调方法?

Bil*_*han 34 activerecord rspec ruby-on-rails ruby-on-rails-3 factory-bot

我在模型中有一个方法:

class Article < ActiveRecord::Base
  def do_something
  end
end
Run Code Online (Sandbox Code Playgroud)

我还对此方法进行了单元测试:

# 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
Run Code Online (Sandbox Code Playgroud)

一切都很好,直到我发现将此方法转移到after_save回调中更好:

class Article < ActiveRecord::Base
  after_save :do_something

  def do_something
  end
end
Run Code Online (Sandbox Code Playgroud)

现在我对这个方法的所有测试都破了.我必须解决它:

  • 没有更具体的调用do_something因为createsave将触发此方法,或者我将遇到重复的数据库操作.
  • 更改createbuild
  • 测试respond_to
  • 使用general model.save而不是单独的方法调用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
    
    Run Code Online (Sandbox Code Playgroud)

测试通过,但我担心的是它不再是具体的方法.如果添加更多,效果将与其他回调混合.

我的问题是,是否有任何美妙的方法来独立测试模型的实例方法,成为回调?

Sub*_*has 68

回调和回调行为是独立的测试.如果要检查after_save回调,则需要将其视为两件事:

  1. 是否为正确的事件触发了回调?
  2. 被调用的函数是做正确的吗?

假设你有一个Article包含许多回调的类,这就是你要测试的方法:

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
Run Code Online (Sandbox Code Playgroud)

这会将您的回调与行为分离.例如,您可以在article.do_something更新其他相关对象时触发相同的回调方法,例如user.before_save { user.article.do_something }.这将适应所有这些.

所以,像往常一样继续测试你的方法.分别担心回调.

编辑:错别字和潜在的误解编辑:改变"做某事"以"触发某事"


Fil*_*uzi 16

您可以使用shoulda-callback-matchers来测试回调的存在而无需调用它们.

describe Article do
  it { should callback(:do_something).after(:save) }
end
Run Code Online (Sandbox Code Playgroud)

如果您还想测试回调的行为:

describe Article do
  ...

  describe "#do_something" do
    it "gives the article something" do
      @article.save
      expect(@article).to have_something
    end
  end
end
Run Code Online (Sandbox Code Playgroud)