はじめに
こんにちは、株式会社TOKOSのツキヤです!
今回はRubyのテストフレームワークであるRSpecについて、導入方法から簡単な使い方までを説明しようと思います!
初学者向けに詳細に解説するのでぜひ最後まで読んでください😎
対象読者
- Ruby(Rails)でテストを書いてみたい人
- RSpecの最新の導入方法を知りたい人
RSpecとは
テストとは
そもそも、テストとは何?🤔 という人のために超簡単にテストの説明をします。
テストとは、自分が書いたプログラムが意図した動作するかどうかを確認する手続きのことです!
例えば、数学の問題集を解くとき、答えが合っているか確認しますよね。プログラムもその動作が予期した通りに行われているかを検証する必要があります。これを行うのが「テスト」です!
テストには種類が色々ありますが、まずはテストとはこういうものなんだということを抑えておいてください💪
RSpecの概要
RSpecは、Ruby言語のテスト用のフレームワーク(gem)です!
他のテストフレームワークと同じく、プログラムの出力や状態を検証し、期待する結果が得られるかをチェックすることができます。
Railsとの親和性も高く、慣れればスムーズにテストを記述できるので、多くのRuby/Rails開発者が使っているgemです✨
なぜRSpecを使うか
RSpecの特徴は記述の読みやすさです!
英語の文法に近い形でテストを記述することができるため、テストコードがそのまま仕様書としての役割も果たせます💪
コードを読むだけで何をテストしているのかが明確にわかるという大きな利点となります。
日本語でも説明自体は書けるので、英語の弱い僕のような日本人でも直感的に読めるはずです!
とはいえ、RubyやRailsのいつもの書き方と若干違うので、書けるようになるまでは一定の練習が必要となります、、、
ここは慣れるまでの辛抱ですので頑張りましょう🥹
競合gem
RSpec以外のテストフレームワークとしては、元々Rubyに組み込まれているMinitestというライブラリがあります。
Railsにももちろん標準でMinitestが含まれていますが、RSpecの方がより自然な記述や詳細な機能を持つので、RSpecを導入することが多いです💪
ググった時に出てくる記事の数もRSpecの方が多いので、迷ったらRSpecを選択しておけば間違いは無いです!
導入方法
それではいよいよRSpecと、それに関係するgem群のインストール・設定を行っていきます!
RSpec以外のgemは無くてもテスト自体はできますが、合ったほうがより効率よくテストができるはずなので是非入れてみましょう💪
RSpec
まずは何と言ってもRSpecです!
# ...
group :development, :test do
gem "rspec-rails"
end
# ...
上記の様にGemfileに追記をしてから $ bundle install を行って下さい!
(Rails前提なので、”rspec-rails”というgemを入れるので注意❗️)
その後、config/application.rbにも追記します。
# ...
config.generators do |g|
g.test_framework :rspec
end
# ...
これだけで準備完了です😎
これで $ rails g controller や $ rails g model をするタイミングで自動でRSpec用のファイルも作成されるようになるので、プロジェクトの最初に導入しておくと良いですね✨
factory_bot_rails
次は、 factory_bot_rails というgemを導入します!
このgemを使うことで、モデル(DB)のデータを簡単に作成することができるようになります!
例えば、emailカラムを持つuserモデルがあったとして、このemailのバリデーションをテストしたいと思います。
その際に、emailカラムに関係無いnameカラムが必須だったら適当に値を入れておいてほしいですよね?
こんな場合にfactory_bot_rails を使えばサクッとデータを作れて検証することができます💪
それでは導入していきます!
と言ってもGemfileに追記して、$ bundle install をするだけです!
# ...
group :development, :test do
gem "rspec-rails"
gem "factory_bot_rails"
end
# ...
細かい使い方は後ほど説明します!
faker
次は、 faker というgemを導入します!
こちらは、factory_bot_railsとの合わせ技として使うgemになります。
先程userテーブルのnameカラムに値を記述しておこうという話をしたのですが、factory_bot_railsだけだと毎回同じ値になります🤔 “太郎” だったらずっと “太郎” が入力されてしまうということですね😂
実際にアプリケーションが運用される際に”太郎”くんだけがuser登録されるというのは少々現実的では無いので、テストとしての精度もやや悪くなりそうですよね😵💫
そこでfakerの出番です!
このgemを使うことで毎回ランダムな値を入れることができるので、実際のアプリケーションに即した形にできます✨
こちらも使い方は後ほど解説するので一旦Gemfileに追記して$ bundle install をしておいてください!
# ...
group :development, :test do
gem "rspec-rails"
gem "factory_bot_rails"
gem "faker"
end
# ...
rubocop-rspec
最後に、rubocop-rspec というgemを紹介します!
こちらは、前提としてRuboCopというgemをインストールしている場合に追加で使うgemです。
RuboCopを導入していない方は下記記事を参考にしてインストール・導入をしてみてください💪
一旦RuboCopが導入されている前提で進めさせていただきます🙏
RuboCopの設定をしない方は飛ばして下さい。
まずは、いつものようにGemfileに追記します。
# ...
group :development, :test do
gem "rspec-rails"
gem "factory_bot_rails"
gem "faker"
gem "rubocop", require: false
gem "rubocop-rspec", require: false
end
# ...
次に.rubocop.ymlに追記をします!
inherit_from: .rubocop_todo.yml
require:
- rubocop-rspec
# ...
これだけで準備完了です!
あとはいつものように $ bundle exec rubocop を行うことで、RSpecに関するlintも行ってくれるようになります✨
RSpecとRuboCopの両方を使用している場合はぜひこのgemも追加してみて下さい😎
テストの記述例 (モデルのバリデーション)
ここからは実際にコードを少し書いてテストをしてみようと思います!
なるべく分かりやすく記述するつもりなので、頑張ってついてきて下さい😏
前提として、name, emailカラムを持つuserテーブルに関して、バリデーションのテストを行おうと思います!
バリデーションは下記のものとします。
# id :bigint not null, primary key
# name(名前) :string(255) not null
# email(メールアドレス) :string(255) not null
class User < ApplicationRecord
# nameカラムは「必須 + 20文字以内」
validates :name, presence: true, length: { maximum: 20 }
# emailカラムは「必須 + ユニーク(一意) + メールアドレスにありがちなパターン」
validates :email, presence: true, uniqueness: true, format: { with: /\A[\w+\-.]+@[a-z\d\-.]+\.[a-z]+\z/i }
end
それではこのバリデーションが上手くはたらいているかどうかのテストを記述していきます!
factory_bot_rails, fakerの設定
まずは、userモデルのインスタンスを作れるようにfactoryの設定をします!
spec/factories/users.rb が無い人はファイルをこの位置に作って下さい!
FactoryBot.define do
factory :user do
name { Faker::Name.name }
sequence(:email) { |n| "user-#{n}@gmail.com" }
end
end
順番に簡単に説明します!
1行目は、これから FactoryBot の記述をするという宣言です。
2行目の :user という記述で、userテーブルのインスタンスを生成するという意味になります。
nameカラムの自動記述の設定です!
波括弧の中の値がuser.nameとして使われます。今回はFakerとの合わせ技です!
Faker::Name.name とすることで、名前っぽいテキストがランダムでここに入ります✨
(ここに “太郎” と書いたらずっと “太郎” が入ります)
Fakerのランダムな生成テキストのジャンルを変えたい場合は以下ドキュメントを参考にしてみて下さい!
Faker::JapaneseMedia::OnePiece.character としたら “Monkey D. Luffy” とか出るのは面白いです🤣
emailカラムの自動記述の設定です!
sequenceという記述が出てきました。これは連続してuserを生成するときに、値をインクリメント(1ずつ増加)しながら記述してくれるという優れものです✨
今回の場合は、1人目のuserは “user-1@gmail.com” が、2人目のuserには “user-2@gmail.com” が入ります。こうすることでユニーク制約を回避しながらuserを何人も生成することができるようになります💪
一旦これでfactoryの記述は以上です、それではテストを記述していきましょう!!
RSpecの記述
spec/models/user_spec.rb に記述していくので、ファイルが無い人はディレクトリを含め作成して下さい!
それではまずは全体の記述をします!
require "rails_helper"
# bundle exec rspec ./spec/models/user_spec.rb で実行
RSpec.describe User do
context "バリデーション" do
it "emailの正規表現が正しいこと" do
user = build(:user, email: "info@to-ko-s.com")
expect(user).to be_valid
user.email = "info@to-ko-s"
expect(user).to be_invalid
user.email = "info.to-ko-s.com"
expect(user).to be_invalid
end
end
end
これはお作法なので、とりあえず記述しておきましょう!
ここもお作法です、テスト対象となるモデルのクラスを書いておきましょう。
context : どういう背景のテストなのかを記述します。ここではバリデーションという背景でテストを行うのでこのような記述をしています!
it : 「〇〇なこと」というような形でテストの内容を記述します! 今回は文字通り「emailの正規表現が正しいこと」をテストしたいのでこのように書いています!
build(:user, email: “info@to-ko-s.com”) : ここでやっと先程のfactoryを使った記述が出てきます!
build(:user) と書くことで User.build(…) と同じ意味で、factoryを使ってbuildすることになります!
更に、第二引数以降に上書きしたい値を キー: バリュー の形で指定もできます✨
今回はemailのバリデーションをテストするので、emailの値は色々な値に変更したいです。なので、このような書き方になっています!
7行目では、まずはバリデーションが正しく通ることを確認したいので、 info@to-ko-s.com という正常なメールアドレスを入れて build します!
expect(user).to be_valid は expect() 部分と be_valid 部分に分けて解説します!
expect() の引数には、テストしたい値を入れます!
be_valid は、expect() の引数にモデルのインスタンス変数が入っている場合、バリデーションが通るかどうかを試してくれます!
そこで、 expect(user).to be_valid とすることで、7行目でbuildしたuserのインスタンス変数がバリデーションを通るかどうかを試しているというわけです😎
こちらでは7,8行目の逆で、バリデーションが通らないことを確かめています!
違う点として、user.emailに通常のメールアドレスではあり得ないような “info@to-ko-s” を入れています! (@マーク以降にドットが入らないのはメールアドレスとしておかしいです!)
プラスで、8行目は be_valid としていましたが、今回は be_invalid としています。こうすることでバリデーションが通らないことをテストしている訳です💪
こちらも基本的には10,11行目と同じことをしているので解説はしません!
RSpecの実行
それではいよいよRSpecを実行してみましょう!
$ bundle exec rspec
上記コマンドでテストが実行されます!
結果としては画像のようになってればOKです✨
逆にテストが通っていないときは赤い文字でfailure(失敗)になるはずです!
試しに、7行目の info@to-ko-s.com を infoto-ko-s.com に変えて実行してみましょう
こうなっていると何かがおかしいので、書き換えて成功の形にしてください💪
おわりに
今回はRSpecの基本的な説明から導入方法、そして簡単なテストの記述までを解説しました。
これらの知識があれば、あなたもRuby/Railsでテストを始める足がかりになるはずです!
テストは品質の高いアプリケーションを作るための強力なツールなので、ぜひRSpecを用いた開発を体験してみてください!
Minitestについても知りたい方がいたら、この本に分かりやすく書かれているので是非参考にしてみて下さい🙏
また、RSpecについて詳しく知りたい場合は以下オススメ記事を読んでみて下さい✨