ruby-on-railsrspeccallbackfactory-botbeforeupdate

How to test before_update callback in rails model with Rspec and FactoryGirl?


I am trying to test the before_update callback of the model bellow.

models/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

spec/models/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

I successfully tested the before_create callback (at least it gave me the correct result). But I don't know how to test the before_update callback. Is there a way to do it?


Solution

  • Warning: this answer is opinionated.

    Test behavior, not implementation.

    A callback is an implementation detail. Don't test it directly. Instead, pretend that you don't know how the model works internally, and test how it behaves.

    If I'm reading the code correctly, the behavior can be described like so:

    When updating an option, the activity_id of each of its suboptions is set to the activity_id of the option.

    Create an option with suboptions. Update it, reload it, and check that the value of each activity_id is correct.

    This will be slower than mocking, but less brittle. Also, the test is much easier to write and maintain.