【Ruby on Rails】RSpecのModel(モデル)テスト書き方サンプル – にょけんのボックス

プログラミング
スポンサーリンク

 

こんにちは、Railsエンジニアにょけんです。

RSpecのModelテストのサンプルコードを書いてみました。

Modelのテストでは、大雑把に分けて以下3つのテストを行います。

  • バリデーション
  • インスタンスメソッド
  • クラスメソッド

今回は、name, email, passwordを持つUserモデルのテストを想定します。

[app/models/user.rb]

class User < ApplicationRecord      # バリデーション    validates :first_name, presence: true    validates :last_name, presence: true    validates :email, presence: true, uniqueness: true      # インスタンスメソッド    def fullname      [first_name, last_name].join(" ")    end      # クラスメソッド    scope :search, ->(term)       { where("LOWER(message) LIKE ?", "%#{term.downcase}%")

 

 

スポンサーリンク

【RSpec Modelテスト】 バリデーション

バリデーションテストはほぼ1〜2行で書けるので、慣れるのにうってつけです。

以下をテストしてみます。

  1. 名前、メアド、パスワードがあれば有効であること
  2. 名前・メアドがなければ無効であること
  3. メアドが重複している場合は無効であること

[app/models/user.rb]

validates :first_name, presence: true  validates :last_name, presence: true  validates :email, presence: true, uniqueness: true  

 

①名前、メアド、パスワードがあれば有効であること

[spec/models/user_spec.rb]

# 名前、メアド、パスワードがあれば有効であること  it "is valid with a first_name, last_name, email, and password" do     @user = User.new(       first_name: "John",      last_name: "Brawn",       email: "test@example.com",       password: "i-am-john"     )    expect(@user).to be_valid  end

作成したインスタンスがバリデーションを通過して有効であるかどうかは、「be_valid」で確認できます。

 

②苗字・名前・メアドがなければ無効であること

[spec/models/user_spec.rb]

# 名前がなければ無効であること  it "is invalid without a first_name" do    @user = User.new(first_name: nil)    expect(@user.valid?).to eq(false)  end    # 苗字がなければ無効であること   it "is invalid without a last_name" do    @user = User.new(last_name: nil)    expect(@user.valid?).to eq(false)  end    # メアドがなければ無効であること   it "is invalid without a email" do    @user = User.new(email: nil)    expect(@user.valid?).to eq(false)  end

 

より高度なテスト

「can’t be blank」などのエラーメッセージが、フラッシュでちゃんと返ってくるかまで確認したい場合は、以下を参考にしてください。

[spec/models/user_spec.rb]

# 名前がなければ無効であること   it "is invalid without a first_name" do    @user = User.new(first_name: nil)    @user.valid?    expect(user.errors[:first_name]).to include("can't be blank")  end    # 苗字がなければ無効であること  it "is invalid without a last_name" do    @user = User.new(last_name: nil)    @user.valid? expect(user.errors[:last_name]).to include("can't be blank")  end    # メアドがなければ無効であること  it "is invalid without a email" do    @user = User.new(email: nil)    @user.valid?    expect(@user.errors[:email]).to include("can't be blank")  end

→first_name, last_name, emailにnilをセットして「valid?メソッド」を呼び出した場合、エラーメッセージが返ってくることを期待(expect)している。

 

③メアドが重複している場合は無効であること

[spec/models/user_spec.rb]

# メアドが重複している場合は無効であること  it "is invalid with a duplicate email address" do    User.create(      first_name: "John"      last_name:  "Brawn",      email:      "test@example.com",      password:   "i-am-john"    )      @user = User.new(       first_name: "Peter",       last_name:  "Smith",      email:      "test@example.com",      password:   "i-am-peter"    )       @user.valid?    expect(@user.valid?).to eq(false)  end

→emailが”test@example.com”のUserを2つ作ろうとした場合に、失敗することを確認

 

スポンサーリンク


【RSpec Modelテスト】 インスタンスメソッド

モデル内に、first_nameとlast_nameを連結する「fullnameメソッド」があるとします。

[app/models/user.rb]

def fullname    [firstname, lastname].join(' ')  end

 

テストデータを作り、メソッドを手動で動かし、テストするイメージです。

[spec/models/user_spec.rb]

it "returns a user's full name" do    @user = User.new(      first_name: "John",      last_name:  "Brawn",      email:      "test@example.com"    )    expect(user.fullname).to eq "John Brawn"  end  

比較的わかりやすいと思いますが、一点だけ注意。

RSpecで等値は、「==」ではなく「eq」を使います。

 

【RSpec Modelテスト】 クラスメソッド

クラスメソッド例として、渡された文字列と一致するUser名を探す「searchメソッド」があるとします。

[spec/models/user_spec.rb]

describe 'User' do    describe '#search' do        # 各テストの前にUserを作成      before do         @user = User.create(          first_name: "John",           last_name: "Brawn",           email: "test@example.com",           password: "i-am-john"         )           @other_user = User.create(          first_name: "Peter",           last_name: "Smith",           email: "test2@example.com",           password: "i-am-peter"         )       end           # "John"で検索した場合      context "search by 'John'" do        it "returns @user" do          expect(User.search("John")).to include(@user)        end          it "doesn't return @other_user" do          expect(User.search("John")).to_not include(@other_user)        end      end        # "Mike"で検索した場合      context "search by 'Mike'" do        # 空を返す        expect(User.search("Mike")).to be_empty      end    end  end

 

スポンサーリンク

Visited 106 times, 1 visit(s) today

コメント

タイトルとURLをコピーしました