[Rails4] Shoulda-matchersを導入する方法


Shoulda-machersを使うと素晴らしく簡潔かつ直感的にテストをかけるようになるので導入してみることに。しかしインストールして試してみたはいいものの、どうにもこうにも NoMethodError: undefined method `validate_numericality_of' などとあらゆるメソッドが無いよ、とエラーが吐かれハマったのでメモ。パーフェクトRuby on Railsのサンプルコードでハマった方は特におすすめ。

環境

  • Rails 4.2.6
  • rspec-rails 3.4.2
  • shoulda-matchers 3.1.1

導入方法

1. Gemfileにrspec-railsとshoulda-matchersを追加

# /Gemfile
# development・test環境双方でrspec-railsが必要
group :development, :test do
  gem "rspec-rails"
end

group :test do
  gem "shoulda-matchers"
end

2. rails_helperにてshoulda-matchersを動かす設定をする

まずはshoulda-matchersを読み込んであげる。

# /spec/rails_helper.rb  
ENV['RAILS_ENV'] ||= 'test'
require File.expand_path('../../config/environment', __FILE__)
# Prevent database truncation if the environment is production
abort("The Rails environment is running in production mode!") if Rails.env.production?
require 'spec_helper'
require 'rspec/rails'
require 'shoulda/matchers' # こいつを追加してあげる

さらに同ファイルで設定を追加する

# /spec/rails_helper.rb  
Shoulda::Matchers.configure do |config|
  config.integrate do |with|
    # 今回はRspecを使うのでこのように設定
    with.test_framework :rspec

    # shoulda-matchersを使いたいテストライブラリを指定
    with.library :active_record
    with.library :active_model
    with.library :action_controller
    # Or, choose the following (which implies all of the above):
    with.library :rails
  end
end

3. spec/models/hoge_spec.rbでrails_helperを読み込む

# /spec/models/hoge.rb
require 'rails_helper'
RSpec.describe Hoge, type: :model do
  (テストコードを書く)
end

これで、ひとまずShoulda-matchersを動かすための設定は完了しました。テストコードを書けば動いてくれます。ってことで、以下でサンプルとして実際のモデルテストを書いてみます。

4. テストコードを書いてRspecを走らせる

# /spec/models/hoge.rb
require 'rails_helper'
RSpec.describe Hoge, type: :model do
  describe '#name' do
    it { should validate_presence_of(:name) }
    it { should validate_length_of(:name).
      is_at_least(4).
      is_at_most(16).
      with_message("4文字以上16文字以下で入力してください")
    }
  end
end

期待に応えるようにモデルにバリデーションを追加してあげます。

# /models/hoge.rb
class Hoge < ActiveRecord::Base

  validates :name, length: { in: 4..16, message: '4文字以上16文字以下で入力してください'}, presence: true

end

そんでもって実行してみると

# ターミナル
tacuma:sample tacuma$ rspec
.

Finished in 0.14455 seconds (files took 6.22 seconds to load)
1 examples, 0 failures

無事、テストが走り、モデルテストが行なえるようになりました。