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?
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:
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.