Edited at

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

More than 1 year has passed since last update.

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


References


Concernの使い方

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


app/models/concerns/naming.rb

# frozen_string_literal: true

module Naming
extend ActiveSupport::Concern

DEFAULT_NAME = "Default Name"

# scope, callback, relation はここに定義
included do
before_create :assign_default_name, unless: :name?

scope :with_name, -> (names) { where(name: names) }
end

# class メソッド
class_methods do
# cattr_reader 使ってもいいですが例なのであえて冗長に書いてます
def default_name
DEFAULT_NAME
end
end

def assign_default_name
self.name = DEFAULT_NAME
end
end



app/models/user.rb

# frozen_string_literal: true

class User < ApplicationRecord
include Naming
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/naming_helper.rb

# frozen_string_literal: true

# 別に module 宣言なくいきなり shared_example_for から始めても
# 問題ないです。
module NamingHelper
shared_examples_for 'naming' do
let(:object_name) { described_class.to_s.underscore.to_sym }

# FactoryGirl入れてる前提でいます
let(:model) { build(object_name) }

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

it { is_expected.to eq(described_class::DEFAULT_NAME) }
end

describe '#assign_default_name' do
context "w/ name" do
before do
model.name = "user1"
model.save!
end

it "not assign default name" do
expect(model.name).to_not equal(described_class::DEFAULT_NAME)
end
end

context "w/o name" do
before do
model.name = ""
model.save!
end

it "assigns default name" do
expect(model.name).to equal(described_class::DEFAULT_NAME)
end
end
end
end
end



spec/models/user_spec.rb

# frozen_string_literal: true

require 'rails_helper'

describe User, type: :model do
# これを書くだけ
it_behaves_like 'naming'
end


これで user_spec.rb が実行される時に Naming のテストケースが呼ばれ、無事テストもDRYでいい感じに書けました。

ただ shared_examples は使いすぎるとテストが読みづらくなるので、テストに関しては過度に DRY にしすぎず、読みやすさ重視で書いた方がいいと個人的には思っています :smiley: :spades:

いろんなところを参考にしました :pray: