記事の内容
RSpecをインストールして動作させるまでの手順
前提
- Ruby 2.3.3
- Rails 5.2.2
- RSpec 3.8
内容
Rialsプロジェクトを作る
以下コマンドを順番に実行してRailsプロジェクトを作る
mkdir rspec_test
cd rspec_test
rails new .
注意
※プロジェクト名をRSpecにするとうまく動かないので注意
RailsプロジェクトにRSpecをインストールする
gemファイルの「test」にRSpecを追加する。
group :test do
...
...
gem 'rspec-rails'
end
gemファイルの内容をインストールする
bundle install
rspecの構成ファイル/構成フォルダを作成する。
// 実行するとspecフォルダができる
rails g rspec:install
テスト対象クラスを作る
今回はtitleカラムを持つTodoモデルをテスト対象とする。
以下のコマンドを実行してテスト対象クラスを作る。
rails g model todo
マイグレーションファイルを下記のように編集する。
class CreateTodos < ActiveRecord::Migration[5.2]
def change
create_table :todos do |t|
t.text :title
t.timestamps
end
end
end
下記のコマンドを実行してマイグレーションを行う。
rails db:migrate
テストコードを作成する
以下のコマンドを実行してテストコードの雛形を作成する。
rails g rspec:model todo
テストコードを記述する。
require 'rails_helper'
RSpec.describe Todo, type: :model do
describe "#title" do
context "空の場合" do
let(:todo){Todo.new(title:"")} #titleが空文字のTodoオブジェクトを生成
it "エラーを返す" do
todo.valid? #バリデーションを実行
expect(todo.errors[:title]).to be_present #期待結果:エラーメッセージが存在する
end
end
context "Nullの場合" do
let(:todo){Todo.new(title:nil)} #titleがNullのTodoオブジェクトを生成
it "エラーを返す" do
todo.valid? #バリデーションを実行
expect(todo.errors[:title]).to be_present #期待結果:エラーメッセージが存在する
end
end
context "値が入っている場合" do
let(:todo){Todo.new(title:"this is title")} #titleに値が入っているTodoオブジェクトを生成
it "エラーを返さない" do
todo.valid? #バリデーションを実行
expect(todo.errors[:title]).to be_blank #期待結果:エラーメッセージが存在しない
end
end
end
end
describeに「テスト概要」を記述して、contextに「テスト条件」を記述して、itに「期待結果」を書く感じ。
期待結果の書き方は、下記の通り。
expect(検証対象変数).to [期待結果]
より詳細なexpectの書き方は、こちらの記事がわかりやすい。
テストを実行する
下記のコマンドを実行してテストを実行する
rspec
下記のような結果が返ってくる。
1) Todo#title 空の場合 エラーを返す
Failure/Error: expect(todo.errors[:title]).to be_present
expected `[].present?` to return true, got false
# ./spec/models/todo_spec.rb:9:in `block (4 levels) in <top (required)>'
2) Todo#title Nullの場合 エラーを返す
Failure/Error: expect(todo.errors[:title]).to be_present
expected `[].present?` to return true, got false
# ./spec/models/todo_spec.rb:17:in `block (4 levels) in <top (required)>'
Finished in 0.04147 seconds (files took 1.89 seconds to load)
3 examples, 2 failures
Failed examples:
rspec ./spec/models/todo_spec.rb:7 # Todo#title 空の場合 エラーを返す
rspec ./spec/models/todo_spec.rb:15 # Todo#title Nullの場合 エラーを返す
「空の場合」と「Nullの場合」はテストに失敗していることがわかる。
「値が入っている場合」は期待通りの結果になっているので、テストが成功していることがわかる。
テスト対象コードを修正する
「空の場合」と「Nullの場合」に、テストの期待結果通りバリデーションエラーが発生するようにコードを修正する。
class Todo < ApplicationRecord
validates :title, presence: true
end
テストを実行する
以下のコマンドを実行してテストを行う。
rspec
下記のような結果が返ってくるはず。
Finished in 0.02788 seconds (files took 0.95229 seconds to load)
3 examples, 0 failures
テスト失敗がなくなっていることがわかる。
(2019/2/2 追記) Subjectを使ったRSpecの書き方
Subjectメソッドを使うと、もっと簡潔に書ける。
require 'rails_helper'
RSpec.describe Todo, type: :model do
describe "#title" do
#テストする対象ロジック
subject{ todo.valid?; todo.errors[:title] }
context "空の場合" do
# titleが空のオブジェクトを作る
let(:todo){Todo.new(title:"")}
# titleが空のときの期待結果を定義する
it { should be_present }
end
context "Nullの場合" do
let(:todo){Todo.new(title:nil)}
it { should be_present }
end
context "値が入っている場合" do
let(:todo){Todo.new(title:"this is title")}
it { should be_blank }
end
end
end
subjectに「テスト対象の処理」を記述して、itに「その期待結果」を記述する。
subjectを使うとitの方の記述が簡単になる。
感想
JUnitしか書いたことがなかったが、RSpecは「振る舞い駆動」のテストケースを書きやすくて良いなと思いました。TDDもやりやすいんじゃないかな。
終わり。