Как тестировать коллбэки ActiveRecord моделей

Иногда непонятно, с какой стороны подойти к сложному коллбэку и как его протестировать. Например, в ситуации с постом:

class Post < ApplicationRecord
  before_save :set_permalink
  after_save :rebuild_preview

  private

  def set_permalink
    self.permalink ||= build_permalink
  end

  def build_permalink
    date.strftime("%Y/%-m/") + title.parameterize("-")
  end

  def rebuild_preview
    Preview.new(self).rebuild
  end
end

Если захотелось протестировать их отдельно, с помощью send, не надо так. Это приватные методы, в любой момент они поменяются или исчезнут.

Тестируйте публичный интерфейс, использующий эти приватные методы. Если коллбэк на after_save/before_save, тестируйте save, если на after_initialize/before_initializenew.

В случае с постом спека выглядела бы так:

describe "#save"
  context "when permalink is NOT set" do
    it "generates it from year, month and title" do
      post = Post.create(
        date: new Date(2016, 07, 07),
        title: "Hello, its me")

      expect(post.permalink).to eq "2016/7/hello-its-me"
    end
  end

  context "when permalink is set" do
    it "preserves it" do
      post = Post.new(
        title: "Some title",
        permalink: "some-special-post")

      expect { post.save }.not_to change { post.permalink }
    end
  end

  it "rebuilds preview" do
    preview = instance_double(Preview, rebuild: true)
    post = Post.new(title: "Some title")
    allow(Preview).to receive(:new).and_return(preview)

    post.save

    expect(preview).to have_received(:rebuild)
  end
end

Вот и все дела.

P. S. Ещё больше постов о программировании, тестах и культуре разработки у меня в Телеграме.