如何使用Rspec和FactoryGirl测试rails模型中的before_update回调?

Lui*_*que 2 rspec ruby-on-rails callback beforeupdate factory-bot

我试图测试下面的模型的before_update回调.

车型/ option.rb:

class Option < ApplicationRecord
  belongs_to :activity

  has_many :suboptions, class_name: "Option", foreign_key: "option_id"

  belongs_to :parent, class_name: "Option", optional: true, foreign_key: "option_id"

  accepts_nested_attributes_for :suboptions, allow_destroy: true,
    reject_if: ->(attrs) { attrs['name'].blank? }

  validates :name, presence: true

  before_create :set_defaults
  before_update :set_updates


  def set_defaults
    self.suboptions.each do |sbp|
      sbp.activity_id = self.activity_id
    end
  end

  def set_updates
    suboptions.each do |child|
      child.activity_id = self.activity_id
    end
  end
end
Run Code Online (Sandbox Code Playgroud)

规格/型号/ option.rb:

require 'rails_helper'

RSpec.describe Option, type: :model do

  describe "Callbacks" do
    it "before_create" do
      suboption = create(:option)
      option = create(:option, suboptions:[suboption])
      option.run_callbacks(:create) {false}
      expect(option.suboptions.first.activity_id).to eq suboption.activity_id
    end

    it "before_update" do

    end
  end



end
Run Code Online (Sandbox Code Playgroud)

我成功测试了before_create回调(至少它给了我正确的结果).但我不知道如何测试before_update回调.有办法吗?

zet*_*tic 7

警告:这个答案是固执己见的.

测试行为,而不是实现.

回调是一个实现细节.不要直接测试.相反,假装您不知道模型如何在内部工作,并测试它的行为方式.

如果我正确地读取代码,可以这样描述行为:

更新选项时,每个子选项的activity_id都设置为选项的activity_id.

使用子选项创建选项.更新它,重新加载它,并检查每个activity_id的值是否正确.

这比嘲弄慢,但不那么脆弱.此外,测试更容易编写和维护.


VAD*_*VAD 6

好的。我会尝试从头开始。

要测试回调,您必须测试它是否会在应该调用时被调用。就这样。

您可能想要准确地测试该方法的代码。但是这些方法通常是私有的,它们确实应该是私有的。而且您根本不应该测试私有方法的代码。如果您无论如何都想这样做,您的测试将与您的私有方法耦合,这并不好。

您可以:set_updates像这样测试 before_update :

let(:option) { Option.create("init your params here") }

it "test callback" do
  expect(option).to receive(:set_updates)
  option.save
end
Run Code Online (Sandbox Code Playgroud)

如果你想测试你的私有方法的代码,你可以这样做

let(:option) { Option.create("init your params here") }

it "test callback" do
  # expect to receive some messages
  # which are in your method code
  # for example
  expect_any_instance_of(Suboption).to receive(:activity_id=)
  option.send(:set_updates)
end
Run Code Online (Sandbox Code Playgroud)

PS你可能想看/听“Rails Conf 2013 The Magic Tricks of Testing by Sandi Metz”。这是非常有帮助的事情。