LoginSignup
6
1

More than 3 years have passed since last update.

【rails】RSpec,factory_botを用いてテストを行う

Last updated at Posted at 2020-05-10

factory_bot_rails導入

gem factory_bot_railsを、RSpecと同じ環境に追加する。

Gemfile
group :development, :test do
  # Call 'byebug' anywhere in the code to stop execution and get a debugger console
  gem 'byebug', platforms: [:mri, :mingw, :x64_mingw]
  gem 'rspec-rails'
  gem 'factory_bot_rails'
end
terminal
$ bundle install

ディレクトリ spec/factories を作成する。
ファイル users.rbを作成する。
テストで使うuserクラスのデフォルトインスタンスを定義する。
※テストの際に、一部を変更して使う。

spec/factories/users.rb
FactoryBot.define do
  factory :user do
    nickname                    {"abe"}
    email                       {"kkk@gmail.com"}
    password                    {"00000000"}
    password_confirmation       {"00000000"}
  end
end

メソッド

buildメソッド

factory_botに記述したクラスをシンボル型で引数に指定してインスタンスを生成します。

#factory_botを利用しない場合
user = User.new(nickname: "abe", email: "kkk@gmail.com", password: "00000000", password_confirmation: "00000000")
#factory_botを利用する場合
user = FacrtoryBot.build(:user)
createメソッド

buildメソッド同様、factory_botに記述したクラスをシンボル型で引数に指定してインスタンスを生成します。
さらにテスト用のDBに値が保存されます。
テストが終了するたびにDBの内容はロールバックされます。

# createしたインスタンスはDBに保存される
user = FactoryBot.create(:user)

factory_botの記法の省略

インスタンスを作成する際に必要となるレシーバであるクラスのFactoryBotという記述を、rails_helper.rbに記述することでuser_spec.rbでの記述を省略することができます。

spec/rails_helper.rb
RSpec.configure do |config|
  ...
  #下記の記述を追加
  config.include FactoryBot::Syntax::Methods
  ...
end
factory_botを利用したインスタンス生成
spec/model/user_spec.rb
require 'rails_helper'
describe User do
  describe '#create' do
    it "nicknameがない場合は登録できないこと" do
      # user = User.new(nickname: "", email: "kkk@gmail.com",password: "00000000", password_confirmation: "00000000")
      user = build(:user, nickname: "")
      user.valid?
      expect(user.errors[:nickname]).to include("can't be blank")
    end

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

バリデーションに関するテストコードを書く

テスト項目

1.nicknameとemail、passwordとpassword_confirmationが存在すれば登録できること
2.nicknameがない場合は登録できないこと
3.emailがない場合は登録できないこと
4.passwordがない場合は登録できないこと
5.passwordが存在してもpassword_confirmationがない場合は登録できないこと
6.nicknameが7文字以上であれば登録できないこと
7.nicknameが6文字以下では登録できること
8.重複したemailが存在する場合登録できないこと
9.passwordが6文字以上であれば登録できること
10.passwordが5文字以下であれば登録できないこと

テストコード

テスト項目に沿って次の通り書く。

spec/model/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: "")
      user.valid?
      expect(user.errors[:nickname]).to include("can't be blank")
    end

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

    #4
    it "passwordがない場合は登録できないこと" do
      user = build(:user, password: "")
      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: "abematv")
      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: "abemat")
      expect(user).to be_valid
    end

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

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

    #10
    it "passwordが5文字以下であれば登録できないこと" do
      user = build(:user, password: "12345", password_confirmation: "12345")
      user.valid?
      expect(user.errors[:password]).to include("is too short (minimum is 6 characters)")
    end
  end
end
テスト実行
terminal
$ bundle exec rspec
2020-05-10 19:22:19 WARN Selenium [DEPRECATION] Selenium::WebDriver::Chrome#driver_path= is deprecated. Use Selenium::WebDriver::Chrome::Service#driver_path= instead.

User
  #create
    nicknameとemail、passwordとpassword_confirmationが存在すれば登録できること
    nicknameがない場合は登録できないこと
    emailがない場合は登録できないこと
    passwordがない場合は登録できないこと
    passwordが存在してもpassword_confirmationがない場合は登録できないこと
    nicknameが7文字以上であれば登録できないこと
    nicknameが6文字以下では登録できること
    重複したemailが存在する場合登録できないこと
    passwordが6文字以上であれば登録できること
    passwordが5文字以下であれば登録できないこと

Finished in 0.10159 seconds (files took 1.61 seconds to load)
10 examples, 0 failures

表示0 failuresにより、予期した通り動作することを確認できた。

be_validマッチャ

expectの引数にしたインスタンスが全てのバリデーションをクリアする場合にパスする。
次の通り書く。

spec/model/user_spec.rb
    it "nickname、email、passwordとpassword_confirmationが存在すれば登録できること" do
      user = build(:user)
      expect(user).to be_valid
    end

テストの原則

①1example、1エクスペクテーション

2つ以上含めると、どちらのエクスペクテーションでエラーが出たのか判別できない。

②期待する結果をわかりやすく書く

it "〜" doの"〜"の部分は、期待する結果を書いておく場所。

③起きて欲しいことと起きてほしくないこと両方をテストする

起きて欲しいことをチェックしたら、起きてほしくない場合にどんな結果が起こるかも想定しその通りになるか確かめる。
予期せぬ動作が残るのを防ぐため。

④境界値をテストする

6文字以上でバリデーションに引っかかる、という条件の場合は「5文字までは正常」と「6文字以上ならば異常」を確かめるようにする。

⑤可読性を考えつつ、適度にDRYにする

テストではわかりやすさを優先する。
その上で「Don't Repeat Yourself」

関連リンク

6
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
1