Rails テストについて 4 (モデル編)


はじめに

テストに拒否反応があるので、まずは整理したいと思います。
整理していくにつれ、拒否反応がなくなってきたかも・・・

少しづつ記事を書いていきます。
Rails テストについて 1
Rails テストについて 2
Rails テストについて 3
もうすでにご存知の方、省略の仕方等ご存知でしたら、ご助言願います。

specファイルの記述を効率化!!

  • factory_botというgemを導入する。

factory_botの導入理由

  • 簡単にダミーのインスタンスを作成することができるGem。
  • 他のファイルで予め各クラスのインスタンスに定めるプロパティを設定しておく。
  • specファイルからメソッドを利用してその通りのインスタンスを作成する。
  • 若干、変わります! しかし、これが楽になります。
  • imageのみなので、実感はないですが、image以外をもしテストする場合、毎回インスタンスを作成するのは面倒です。なので、factory_botを導入しました!
  • 今はパッとしませんが、読み進めていただければ、理解できると思います!
photo_spec.rb
(導入前)

require 'rails_helper'
describe Photo do
  describe '#create' do
    it "imageがない場合は投稿できないこと" do
      photo = Photo.new(image: "")
      photo.valid?
      expect(photo.errors[:image]).to include("は必要です。")
    end
  end
end


(導入後)

require 'rails_helper'
describe Photo do
  describe '#create' do
    it "imageがない場合は投稿できないこと" do
      photo = build(:photo, image: nil)
      photo.valid?
      expect(photo.errors[:image]).to include("は必要です。")
    end
  end
end

Gemfileに追記

group :development, :test do
  #省略
  gem 'rspec-rails'
  gem 'factory_bot_rails'
end

そして、bundle installです!

factoriesディレクトリの作成と記述

  • specディレクトリ直下に「factories」というディレクトリを作成する。
  • その中に、作成したインスタンスの複数形のファイル名でRubyのファイルを作成する。

  • 上記画像の緑文字ですねー!

  • そして、コードを記述!

photos.rb
FactoryBot.define do

  factory :photo do
    image              {"image.png"}
  end

end
  • specファイルの中で特定のメソッドにより簡単にインスタンスを生成したり、DBに保存したりできるようになりました!(今回は imageのみ)

factory_botを導入したことにより、使えるメソッド(以下userインスタンス)

buildメソッド

  • 引数にシンボル型で取ったクラス名のインスタンスを、factory_botの記述をもとに作成します。
  • 例えば前述のusers.rbが存在する場合、下記2つの変数userの値は同じ値になります。
#factory_botを利用しない場合
user = User.new(nickname: "raiga", email: "[email protected]", password: "00000000", password_confirmation: "00000000")

#factory_botを利用する場合
user = FactoryBot.build(:user)
  • 記述量が減りました!!!

createメソッド

  • buildとほぼ同じ働きをしますが、createの場合はテスト用のDBに値が保存されます。
  • 注意すべき点として、1回のテストが実行され、終了する毎にテスト用のDBの内容がロールバックされます。(保存された値がすべて消去されてしまう)
  • 従って、binding.pry等でテストの実行を一時停止しないとテスト用のDBに保存された値をSequel Pro等で確認することはできません。
#createしたインスタンスはDBに保存される
user = FactoryBot.create(:user)

FactoryBotの記述省略

  • 記述量は減りましたが、上記「factory_botの導入理由」に記述したコードにはFactoryBotは記述していません。
  • 省略方法があります。
  • spec/rails_helper.rbを以下のように編集!
rails_helper.rb
#省略
RSpec.configure do |config|
  #下記の記述を追加
  config.include FactoryBot::Syntax::Methods

  #省略

end
  • そうすると、FactoryBotの記述がなくても問題ありません。

テストコードの書き方(参考)

  • nickname、email、passwordとpassword_confirmationが存在すれば登録できること
  • nicknameがない場合は登録できないこと
  • emailがない場合は登録できないこと
  • passwordがない場合は登録できないこと
  • passwordが存在してもpassword_confirmationがない場合は登録できないこと
  • nicknameが7文字以上であれば登録できないこと
  • nicknameが6文字以下では登録できること
  • 重複したemailが存在する場合登録できないこと
  • passwordが6文字以上であれば登録できること
  • passwordが5文字以下であれば登録できないこと
user_spec.rb
require 'rails_helper'

describe User do
  describe '#create' do
    # 1
    it "nicknameとemail、passwordとpassword_confirmationが存在すれば登録できること" do
      user = build(:user)
      expect(user).to be_valid
    end

    # 2
    it " nicknameがない場合は登録できないこと" do
      user = build(:user, nickname: nil)
      user.valid?
      expect(user.errors[:nickname]).to include("can't be blank")
    end

    # 3
    it "emailがない場合は登録できないこと" do
      user = build(:user, email: nil)
      user.valid?
      expect(user.errors[:email]).to include("can't be blank")
    end

    # 4
    it "passwordがない場合は登録できないこと" do
      user = build(:user, password: nil)
      user.valid?
      expect(user.errors[:password]).to include("can't be blank")
    end

    # 5
    it "passwordが存在してもpassword_confirmationがない場合は登録できないこと" do
      user = build(:user, password_confirmation: "")
      user.valid?
      expect(user.errors[:password_confirmation]).to include("doesn't match Password")
    end

    # 6
    it " nicknameが7文字以上であれば登録できないこと" do
      user = build(:user, nickname: "aaaaaaa")
      user.valid?
      expect(user.errors[:nickname]).to include("is too long (maximum is 6 characters)")
    end

    # 7
    it "nicknameが6文字以下では登録できること " do
      user = build(:user, nickname: "aaaaaa")
      expect(user).to be_valid
    end

    # 8
    it " 重複したemailが存在する場合は登録できないこと " do
      user = create(:user)
      another_user = build(:user, email: user.email)
      another_user.valid?
      expect(another_user.errors[:email]).to include("has already been taken")
    end

    # 9
    it " passwordが6文字以上であれば登録できること " do
      user = build(:user, password: "000000", password_confirmation: "000000")
      user.valid?
      expect(user).to be_valid
    end

    # 10
    it " passwordが5文字以下であれば登録できないこと " do
      user = build(:user, password: "00000", password_confirmation: "00000")
      user.valid?
      expect(user.errors[:password]).to include("is too short (minimum is 6 characters)")
    end
  end
end

テスト編、続きます!(次はコントローラーテスト!難しい!)

さいごに

日々勉強中ですので、随時更新します。
皆様の復習にご活用頂けますと幸いです。