旧ブログ(ISSEN)から移行しました

【Rails7】RSpecとは? 導入から使い方まで【初学者向け】

【Rails7】RSpecとは? 導入から使い方まで【初学者向け】

西原月熙
西原月熙11分で読めます

はじめに

こんにちは、株式会社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です!

Gemfile
# ...
group :development, :test do
  gem "rspec-rails"
end
# ...

上記の様にGemfileに追記をしてから $ bundle installを行ってください!
(Rails前提なので、rspec-railsというgemを入れるので注意!)

その後、config/application.rbにも追記します。

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をするだけです!

Gemfile
# ...
group :development, :test do
  gem "rspec-rails"
  gem "factory_bot_rails"
end
# ...

細かい使い方は後ほど説明します!

faker

次は、 fakerというgemを導入します!
こちらは、factory_bot_railsとの合わせ技として使うgemになります。
先程usersテーブルのnameカラムに値を記述しておこうという話をしたのですが、factory_bot_railsだけだと毎回同じ値になります🤔
"太郎"だったらずっと"太郎"が入力されてしまうということですね😂
実際にアプリケーションが運用される際に"太郎"くんだけがusersテーブルに登録されるというのは少々現実的では無いので、テストとしての精度もやや悪くなりそうですよね😵‍💫
そこでfakerの出番です!
このgemを使うことで毎回ランダムな値を入れることができるので、実際のアプリケーションに即した形にできます✨

こちらも使い方は後ほど解説するので一旦Gemfileに追記して$ bundle installをしておいてください!

Gemfile
# ...
group :development, :test do
  gem "rspec-rails"
  gem "factory_bot_rails"
  gem "faker"
end
# ...

rubocop-rspec

最後に、rubocop-rspecというgemを紹介します!
こちらは、前提としてRuboCopというgemをインストールしている場合に追加で使うgemです。
RuboCopを導入していない方は下記記事を参考にしてインストール・導入をしてみてください💪

【Rails】RuboCopの導入 ~ おすすめルールの設定方法

RuboCopの導入方法からおすすめの設定ファイルまで詳しく解説。rubocop-rails・rubocop-performanceの設定や、チーム開発で使いやすい緩めのルール設定例をコピペで使える形式で紹介します。

一旦RuboCopが導入されている前提で進めさせていただきます🙏
RuboCopの設定をしない方は飛ばしてください。
まずは、いつものようにGemfileに追記します。

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に追記をします!

.rubocop.yml
inherit_from: .rubocop_todo.yml
 
require:
  - rubocop-rspec
# ...

これだけで準備完了です!
あとはいつものように $ bundle exec rubocopを行うことで、RSpecに関するlintも行ってくれるようになります✨
RSpecとRuboCopの両方を使用している場合はぜひこのgemも追加してみてください😎

テストの記述例 (モデルのバリデーションを例に)

ここからは実際にコードを少し書いてテストをしてみようと思います!
なるべく分かりやすく記述するつもりなので、頑張ってついてきてください😏

前提として、name, emailカラムを持つusersテーブルに関して、バリデーションのテストを行おうと思います!
バリデーションは下記のものとします。

app/models/user.rb
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が無い人はファイルをこの位置に作ってください!

spec/factories/users.rb
FactoryBot.define do
  factory :user do
    name { Faker::Name.name }
    sequence(:email) { |n| "user-#{n}@gmail.com" }
  end
end

順番に簡単に説明します!

1,2行目

1行目は、これからFactoryBotの記述をするという宣言です。
2行目の:userという記述で、usersテーブルのインスタンスを生成するという意味になります。

3行目

nameカラムの自動記述の設定です!
波括弧の中の値がuser.nameとして使われます。今回はfakerとの合わせ技です!
Faker::Name.nameとすることで、名前っぽいテキストがランダムでここに入ります✨
(ここに"太郎"と書いたらずっと"太郎"が入ります)

fakerのランダムな生成テキストのジャンルを変えたい場合は以下ドキュメントを参考にしてみてください!

GitHub - faker-ruby/faker: A library for generating fake data such as names, addresses, and phone numbers.

A library for generating fake data such as names, addresses, and phone numbers. - faker-ruby/faker

github.com
ツキヤツキヤ

Faker::JapaneseMedia::OnePiece.characterとしたら "Monkey D. Luffy" とか出るのは面白いです🤣

4行目

emailカラムの自動記述の設定です!
sequenceという記述が出てきました。これは連続してuserを生成するときに、値をインクリメント(1ずつ増加)しながら記述してくれるという優れものです✨
今回の場合は、1人目のuser"user-1@gmail.com" が、2人目のuserには "user-2@gmail.com" が入ります。こうすることでユニーク制約を回避しながらuserを何人も生成できるようになります💪

一旦これでfactoryの記述は以上です、それではテストを記述していきましょう!!

RSpecの記述

spec/models/user_spec.rbに記述していくので、ファイルが無い人はディレクトリを含め作成してください!
それではまずは全体の記述をします!

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

1行目

これはお作法なので、とりあえず記述しておきましょう!

4行目

ここもお作法です、テスト対象となるモデルのクラスを書いておきましょう。

5行目

context : どういう背景のテストなのかを記述します。ここではバリデーションという背景でテストを行うのでこのような記述をしています!

6行目

it :「〇〇なこと」というような形でテストの内容を記述します! 今回は文字通り「emailの正規表現が正しいこと」をテストしたいのでこのように書いています!

7行目

build(:user, email: "info@to-ko-s.com") : ここでやっと先程のfactoryを使った記述が出てきます!
build(:user) と書くことで User.build(...) と同じ意味で、factoryを使ってbuildすることになります!
さらに、第二引数以降に上書きしたい値を[キー: バリュー] の形で指定もできます✨
今回はemailのバリデーションをテストするので、emailの値は色々な値に変更したいです。なので、このような書き方になっています!

7行目では、まずはバリデーションが正しく通ることを確認したいので、 "info@to-ko-s.com" という正常なメールアドレスを入れてbuildします!

8行目

expect(user).to be_validexpect() 部分とbe_valid部分に分けて解説します!
expect() の引数には、テストしたい値を入れます!
be_validは、expect() の引数にモデルのインスタンス変数が入っている場合、バリデーションが通るかどうかを試してくれます!

そこで、 expect(user).to be_validとすることで、7行目でbuildしたuserのインスタンス変数がバリデーションを通るかどうかを試しているというわけです😎

10,11行目

こちらでは7,8行目の逆で、バリデーションが通らないことを確かめています!
違う点として、user.emailに通常のメールアドレスではあり得ないような "info@to-ko-s" を入れています! (@マーク以降にドットが入らないのはメールアドレスとしておかしいです!)
プラスで、8行目はbe_validとしていましたが、今回はbe_invalidとしています。こうすることでバリデーションが通らないことをテストしている訳です💪

13,14行目

こちらも基本的には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について詳しく知りたい場合は以下オススメ記事を読んでみてください✨

使えるRSpec入門・その1「RSpecの基本的な構文や便利な機能を理解する」 - Qiita

はじめに RSpecは難しい、よくわからない、といったコメントをときどき見かけます。 確かにちょっと独特な構文を持っていますし、機能も結構多いので「難しそう」と感じてしまう気持ちもわかります。 (構文については僕も最初見たときに「うげっ、なんか気持ちわるっ」と思った記憶が...

qiita.com

この記事を書いた人

西原月熙
西原月熙

TOKOSのテックリード。上流工程からコーディング、インフラ系まで色々やっている器用貧乏です。最近は特にフロントエンドのキャッチアップに力を入れています💪 好きな音楽はボーカロイドです🤖