なぜテストコードを書くのか
アプリケーションが、想定通り正しく動くのか、確認するため。
Ruby on Railsでは、アプリケーションのテストコードを記述する機能を、RSpecというGemを使うことで便利に実装できる。
- RSpecを導入する
① まず、RSpecのGemを導入する
Gemfile
group :development, :test do
( ~省略~ )
gem 'rspec-rails', '~> 4.0.0'
end
Gemfileを変更したので、
~ frima-app % bundle install
② RSpecをアプリ内にインストールする
~ frima-app % rails g rspec:install
③ .rspecファイルに、記述する
テストコードの結果を、ターミナル上で表示するため。
( ~省略~ )
--format documentation
- FactoryBotを導入する
FactoryBot:
インスタンスをまとめられるGem。 テストのときに毎回記述していた、ユーザー生成の記述などを、他のファイルに一まとめにして、各テストで用いるときに使う。
①Gemfile
group :development, :test do
( ~省略~ )
gem 'factory_bot_rails'
end
% bundle install
②テストコードと、FactoryBotの記述をするファイルを、同時に作る
% rails g rspec:model user
③ FactoryBotで、インスタンスを一まとめに
FactoryBot.define do
factory :user do
nickname {'furima'}
email {'furima@example'}
password {'123456'}
password_confirmation {password}
end
end
④ FactoryBotの使い方
RSpec.describe User, type: :model do
describe 'ユーザー新規登録' do
before do
@user = FactoryBot.build(:user) # Userのインスタンス生成
end
context '新規登録できないとき’
it 'emailが同じだと登録できない' do
@user.save
another_user =FactoryBot.build(:user)
another_user.email = @user.email
another_user.valid?
expect(another_user.errors.full_messages).to include("Email has already been taken")
end
end
end
- ランダムな値を生成するFakerを導入する
④のエラー文のように、アプリ内で重複したemailを使えないようにする場合、Fakerを使ったほうが良い。なぜなら、複数のテストを行う際に、FactoryBotで固定のemailで複数回試すため、「すでにemailの重複したインスタンスが存在する」といったような形でエラーが出るかもしれないから。
Gemfile
group :development, :test do
( ~省略~ )
gem 'faker'
end
% bundle install
そして、2-③をFakerを使って表してみると、、、
FactoryBot.define do
factory :user do
nickname {'furima'}
email {Faker::Internet.free_email}
password {Faker::Internet.password(min_length: 6)}
password_confirmation {password}
end
end
- テストコードを実行する
% bundle exec rspec spec/models/user_spec.rb
5. 完成版
FactoryBot.define do
factory :user do
nickname {'furima'}
email {Faker::Internet.free_email}
password {Faker::Internet.password(min_length: 6)}
password_confirmation {password}
end
end
require 'rails_helper'
RSpec.describe User, type: :model do
describe 'ユーザー新規登録' do
before do
@user = FactoryBot.build(:user)
end
context '新規登録できる時' do
it '全ての値が正しく入力されていれば保存できる' do
expect(@user).to be_valid
end
it 'emailが@を含めば登録できる' do
@user.email= 'test@test.com'
expect(@user).to be_valid
end
it 'nicknameが10文字以下なら登録できる' do
@user.nickname='testtestte'
expect(@user).to be_valid
end
it 'passwordとpassword_confirmationが6文字以上であれば登録できる' do
@user.password='123456'
@user.password_confirmation='123456'
expect(@user).to be_valid
end
it 'passwordとpassword_confirmationが6文字以上であれば登録できる' do
@user.password='123456'
@user.password_confirmation='123456'
expect(@user).to be_valid
end
end
context '新規登録できない時' do
it 'nicknameが空では登録できない' do
@user.nickname=''
@user.valid?
expect(@user.errors.full_messages).to include("Nickname can't be blank")
end
it 'emailが空では登録できない' do
@user.email=''
@user.valid?
expect(@user.errors.full_messages).to include("Email can't be blank")
end
it 'emailが全角では登録できない' do
@user.email='123@123'
@user.valid?
expect(@user.errors.full_messages).to include("Email is invalid")
end
it 'emailが同じだと登録できない' do
@user.save
another_user = FactoryBot.build(:user)
another_user.email=@user.email
another_user.valid?
expect(another_user.errors.full_messages).to include("Email has already been taken")
end
it 'emailが@を含まないと登録できない' do
@user.email='testtest.com'
@user.valid?
expect(@user.errors.full_messages).to include("Email is invalid")
end
it 'passwordが空では登録できない' do
@user.password=''
@user.valid?
expect(@user.errors.full_messages).to include("Password can't be blank")
end
it 'passwordが5文字以下だと登録できない' do
@user.password='12345'
@user.valid?
expect(@user.errors.full_messages).to include("Password is too short (minimum is 6 characters)")
end
it 'passwordとpassword_confirmationが不一致だと登録できない' do
@user.password='123456'
@user.password_confirmation='234567'
@user.valid?
expect(@user.errors.full_messages).to include("Password confirmation doesn't match Password")
end
end
end
end