まえがき
本記事は、DMM WEBCAMP Advent Calendar 2023 8日目記事です。
Ruby on Railsを中心に、DWCメンター・卒業生が記事を投稿しておりますので、是非他の記事もご確認ください!
はじめに
こんにちは、DMM WEBCAMP メンターの @ukwhatn です。
本カレンダー4回目の担当日となりますが、今日はRuby on RailsにおけるRSpecの使い方について説明していきます。
RSpecとは?
RSpecは、Ruby 向けの BDD(Behavior-Driven Development=振る舞い駆動開発)フレームワークです。
主にRubyで書かれたアプリケーションの挙動・機能をテストするために利用され、人間が読みやすい形式でのテストコード記述によって「テストからアプリケーションの振る舞いがわかる」というメリットも持っています。
詳しいことは他の記事におまかせしますが、要は「テストを簡単にかけるいい感じのフレームワーク」だと思っていただければ良いと思います。
RailsアプリでRSpecを使ってみる
ここからは、Rails6.1〜7.xのRailsアプリを対象とした記述となります。
主にGemのバージョンなどが異なりますので、適宜読み替えてください。
1. Gemfile に追記する
RailsアプリのGemfileに以下の記述を追記してください。
group :development, :test do
gem 'rspec-rails', '~> 6.1.0'
gem 'factory_bot_rails'
gem 'faker'
end
rspec-rails
はRSpecをRailsアプリケーション内で利用するためのアダプタです。
ここのバージョンがRailsのバージョンによって異なるので、公式のREADMEを確認してください。
また、factory_bot_rails
はテストデータ(ActiveRecordモデル)のセットアップをサポートしてくれるライブラリ、faker
はテストデータのダミー値を生成するときに便利なライブラリです。
rspec-rails
と一緒に利用されることが多いGemなので、これも抑えておきましょう。
それぞれの使い方はこの後説明していきます。
2. bundle install
bundle installでGemをインストールします
bundle install
3. RSpecをセットアップする
以下のコマンドを使って、RSpecの初期セットアップを実行します。
rails generate rspec:install
これにより、以下のファイルが生成されます。
$ rails g rspec:install
create .rspec
create spec
create spec/spec_helper.rb
create spec/rails_helper.rb
ここから主に使っていくのはspec
フォルダの中身になるので、ここが作成できているか確認しておきましょう。
4. RSpec用のモデルを追記する
RSpecでテストしたいモデルのテストファイルを生成します。
rails g rspec:model book
rails g model
コマンドとほぼ同じ記法で大丈夫です。
これでspec/models/books_spec.rb
とspec/factories/books.rb
ができていればOKです。(前者はrails g model
のときに既に作成されているかもしれません)
5. FactoryBotの設定を行う
ここで、先程Gemfileに記載したFactoryBotとFakerを使っていきます。
今回は、無難にtitle, authorのカラムがあることにしましょう。
FactoryBot.define do
factory :user do
# --- ここから記述していきます ---
# 本のタイトルや著者名がランダムに生成されます
title { Faker::Book.title }
author { Faker::Book.author }
# --- ここまで記述します ---
end
end
これで、Factorybot.build(:user)
でランダムに生成された値が投入されたuserモデルのインスタンスが作成されるようになりました。
このようなBook
に特化した生成メソッドなどが豊富にあるのがFakerのいいところです。
他にもFaker::Internet.email
でメールアドレス、Faker::Internet.password
でパスワードなどが生成できます。
詳しくは公式docsを確認してください。
試しにrails c
で見てみると、
$ rails c
Loading development environment (Rails 7.0.8)
irb(main):001> FactoryBot.create(:book)
TRANSACTION (0.0ms) begin transaction
Book Create (0.2ms) INSERT INTO "books" ("title", "author", "created_at", "updated_at") VALUES (?, ?, ?, ?) [["title", "The Last Temptation"], ["author", "Lyman Botsford"], ["created_at", "2023-12-07 14:35:42.760574"], ["updated_at", "2023-12-07 14:35:42.760574"]]
TRANSACTION (0.2ms) commit transaction
=>
#<Book:0x0000000109947fa0
id: 1,
title: "The Last Temptation",
author: "Lyman Botsford",
created_at: Thu, 07 Dec 2023 14:35:42.760574000 UTC +00:00,
updated_at: Thu, 07 Dec 2023 14:35:42.760574000 UTC +00:00>
良い感じですね。
6. テストコードを書く
それでは、このBookモデルに対するテストコードを書いていきます。
spec/models/spec_book.rb
を開き、
pending "add some examples to (or delete) #{__FILE__}"
を削除します。
それから、以下のように記述していきましょう。
require 'rails_helper'
RSpec.describe Book, type: :model do
# ここからテストスタート
# 作成に対するテスト
describe 'create' do
# FactoryBotを使ってbookを作成
let(:book) { FactoryBot.build(:book) }
# まずは正しいデータが作成されるかをテスト
context 'with valid attributes' do
it 'is valid with a title and author' do
expect(book).to be_valid
end
end
# 異常系のテスト
context 'with invalid attributes' do
# titleがない場合のテスト
it 'is invalid without a title' do
book.title = nil
expect(book).to be_invalid
end
# authorがない場合のテスト
it 'is invalid without a author' do
book.author = nil
expect(book).to be_invalid
end
# titleが31文字以上の場合のテスト
it 'is invalid with a title that has more than 31 characters' do
book.title = 'a' * 31
expect(book).to be_invalid
end
# authorが31文字以上の場合のテスト
it 'is invalid with a author that has more than 31 characters' do
book.author = 'a' * 31
expect(book).to be_invalid
end
end
end
end
内容はだいたいコメントの通りです。
最初に作ったbookに対し、それぞれ値を入れ替えてバリデーションに通るかを試していきます。
なお、book
の内容は各テストで独立しているので、authorがない場合のテスト
のときにtitle
までnil
になっているわけではありません。
出力は
Book
create
with valid attributes
is valid with a title and author
with invalid attributes
is invalid without a title
is invalid without a author
is invalid with a title that has more than 31 characters
is invalid with a author that has more than 31 characters
Finished in 0.10826 seconds (files took 0.61249 seconds to load)
5 examples, 0 failures
のようになるはずです。
テストは正常系・異常系などのカテゴリごとにcontext
を使って区切ると良いでしょう。
7. あとは色々書いていく
あとは必要に応じて色々書いていけば良いです。
使えるRSpec入門・その1「RSpecの基本的な構文や便利な機能を理解する」 などはかなり参考になりますので、目を通してみてください。
また、モデルだけでなくメソッドやアクションに対するテストもできます。
JunichiIto/everydayrails-rspec-jp-2022などはサンプルとして優秀ですので、是非specフォルダを覗いてみてください。
如何でしたでしょうか。
普段あまりテストを書かないという方は、バリデーションがうまく働いているかを確認するところからRSpecに入門してみませんか?