初学者です。備忘録がてらまとめました。
- Ruby2.6.5
- Rails6.0.0
テストコードを効率的に書きたい!
テストコードが冗長になって読みにくい..そんな時に使えるFactoryBot!
例えばUserのログイン機能をテストしたいとします。
以下が使ってないverです。
RSpec.describe User, type: :model do
describe 'ユーザー新規登録' do
it 'nicknameが空では登録できない' do
user = User.new(nickname: '', email: 'test@example', password: '000000', password_confirmation: '000000')
user.valid?
expect(user.errors.full_messages).to include("Nickname can't be blank")
end
次にFactoryBot使用verです。
RSpec.describe User, type: :model do
describe 'ユーザー新規登録' do
it 'nicknameが空では登録できない' do
user = FactoryBot.build(:user) # Userのインスタンス生成
user.nickname = '' # nicknameの値を空にする
user.valid?
expect(user.errors.full_messages).to include "Nickname can't be blank"
end
FactoryBotとは、インスタンスをまとめるGemのことです。別ファイルに書き込んだものを、書くテストコードで使い回しできるんです。
めっちゃ変わった!というわけではありませんが、目視でわかりますね。使ってないと横に伸びてます。
このコードだけだと、効果がわかりづらいのですが、テストコードはあら有る状況を書いていくもの..
FactoryBotを使わないと、チリも詰まればなんとやらと言いますが、まさしくそれで、可読性も下がってしまいます。
ですので、テストコードを書く際は積極的に使いましょう!
FactoryBotの導入
Gemの一種ですので、いつもの流れです。
が、記述する箇所に注意してください!
Gemfileのgroup :development, :test do ~ endの中です。
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', '~> 4.0.0'
gem 'factory_bot_rails' ←ここです
end
いつものbundle install!
ターミナル
% bundle install
インスタンスをまとめるファイルの作成
FactoryBotを書く、もしくはインスタンスをまとめるファイルを作成します。
※ここではUserモデルのテストコードで進めていきます。
spec/factories /users.rb ←これを作ります
具体的な書き方
生成したファイル内の記述例がこちらです。
Fakerを使用したほうが良いパターンもあります。詳しくはこの後に記述しています。
spec/factories/users.rb
FactoryBot.define do
factory :user do
nickname {'test'}
email {'test@example'}
password {'000000'}
password_confirmation {password}
end
end
この設定したインスタンスをテスト内で使う場合、 FactoryBot.build(:user) と書く必要があります!
さっき上で見たテストコードを使って修正します。
spec/models/user_spec.rb
RSpec.describe User, type: :model do
describe 'ユーザー新規登録' do
it 'nicknameが空では登録できない' do
user = FactoryBot.build(:user) # Userのインスタンス生成
user.nickname = '' # nicknameの値を空にする
user.valid?
expect(user.errors.full_messages).to include "Nickname can't be blank"
end
これをさらに可読化させます。
RSpec.describe User, type: :model do
before do ←ここに注目!
@user = FactoryBot.build(:user)
end
describe 'ユーザー新規登録' do
it 'nicknameが空では登録できない' do
@user.nickname = ''
@user.valid?
expect(@user.errors.full_messages).to include "Nickname can't be blank"
end
@userとbeforeを活用することで、**user = FactoryBot.build(:user)**を繰り返し書かずに済みます。
ここで before と build が出てきたので簡単に触れましょう。
before
それぞれのテストコードを実行する前に、先に実行してくれます。コントローラーでもたまに使ってましたね!
今回はこのbeforeくんのおかげでちゃっちゃと記述できています。とっても効率的!
build
ActiveRecordのnewメソッドと同じように働きます。
build=組み立てる、築くって意味ですもんね!
テストコードがかけたら、下記のコマンドを実行します。
ターミナル
bundle exec rspec spec/models/user_spec.rb
値をランダム生成するFaker
ここまでは、FactoryBot内の詳細を自分で記述していました。(email=test@example、nickname=testなど)
ですが、もしemailなどのバリデーションで一意性などの設定をしていた場合、このままだとテストが通らなくなってしまいます。
そんな時に使うのがFakerです!
Faker
ランダムな値を生成するGemです。メールアドレス、人名、パスワードなど、さまざまな意図に応じたランダムな値を生成してくれます。
Fakerの公式GitHub
Qiita・Fakerのチートシート
Fakerの導入
こちらもGemfileに記述し、bundle installしましょう!
今回もgroup :development, :test doに書いてくださいね!
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', '~> 4.0.0'
gem 'factory_bot_rails'
gem 'faker'
end
Fakerバージョンに記述を変更してみる
emailだけでもいいのですが、せっかくですから三つともFakerバージョンにしてみましょう!
spec/factories/users.rb
FactoryBot.define do
factory :user do
nickname {Faker::Name.initials(number: 2)}
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
緑色で通れば成功です!
お疲れ様でした!