ActiveSupport::Concernの使い方とテスト(RSpec)

  • 58
    Like
  • 0
    Comment

何回も書くことないかなと思ってましたが、Concernsのテスト書くことになって前に書いたやつ見に行ったりしたのでこの際自分に都合のいい形でまとめておきました。

References

Concernの使い方

モデル間で共有したいmoduleを下記のように定義

app/models/concerns/common_module.rb
module CommonModule
  extend ActiveSupport::Concern

  # scope, callback, relation はここに定義  
  included do
    before_create :set_default_name, unless: :name
    scope :with_foo_id, -> (foo_id) { where(foo_id: foo_id) }
  end

  def set_default_name
    self.name = 'Default Name'
  end

  def calculate_age
    Date.today.year - birth_day.year
  end

  # classメソッドは ClassMethods モジュール内に定義  
  module ClassMethods
    def class_method
      puts 'hogehoge'
    end
  end
end
app/models/user.rb
class User < ActiveRecord::Base
  include CommonModule
end

テスト(RSpec)

spec/rails_helper.rb
# ...
require 'rspec/rails'

# spec/support/ 以下のファイルがちゃんと require されるようになってるか確認
Dir[Rails.root.join('spec/support/**/*.rb')].each { |f| require f }
spec/support/models/concerns/common_module_helper.rb
# 別に module 宣言なくいきなり shared_example_for から始めても
# 問題ないです。
module CommonModuleHelper
  shared_example_for 'common_module' do
    let(:obj_name) { described_class.to_s.underscore.to_sym }
    # FactoryGirl入れてる前提でいます  
    let(:model) { create(obj_name) }

    # 普通にテスト書くのと同じようにテストを書きます
    describe '#calculate_age' do
      subject { model.calculate_age }

      it { is_expected.to eq(Date.today.year - model.birthday.year) }
    end
  end
end
spec/models/user_spec.rb
require 'rails_helper'

describe User, type: :model do

  # これを書くだけ
  it_behaves_like 'common_module'

end

これで user_spec.rb が実行される時に CommonModule のexamplesが呼ばれ, 無事テストもいい感じに書けました。

いろんなところを参考にしたんだと思います。