Edited at

RSpecのインストール方法と動かし方


記事の内容

RSpecをインストールして動作させるまでの手順


前提


  • Ruby 2.3.3

  • Rails 5.2.2

  • RSpec 3.8


内容


Rialsプロジェクトを作る

以下コマンドを順番に実行してRailsプロジェクトを作る


console

mkdir rspec_test

cd rspec_test
rails new .

注意

※プロジェクト名をRSpecにするとうまく動かないので注意


RailsプロジェクトにRSpecをインストールする

gemファイルの「test」にRSpecを追加する。


Gemfile

group :test do

...
...
gem 'rspec-rails'
end

gemファイルの内容をインストールする


console

bundle install


rspecの構成ファイル/構成フォルダを作成する。


console

// 実行するとspecフォルダができる

rails g rspec:install


テスト対象クラスを作る

今回はtitleカラムを持つTodoモデルをテスト対象とする。

以下のコマンドを実行してテスト対象クラスを作る。


console

rails g model todo


マイグレーションファイルを下記のように編集する。


20190202080103_create_todos.rb

class CreateTodos < ActiveRecord::Migration[5.2]

def change
create_table :todos do |t|
t.text :title
t.timestamps
end
end
end

下記のコマンドを実行してマイグレーションを行う。


console

rails db:migrate



テストコードを作成する

以下のコマンドを実行してテストコードの雛形を作成する。


console

rails g rspec:model todo


テストコードを記述する。


todo_spec.rb

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の書き方は、こちらの記事がわかりやすい。


テストを実行する

下記のコマンドを実行してテストを実行する


console

rspec


下記のような結果が返ってくる。


console

  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の場合」に、テストの期待結果通りバリデーションエラーが発生するようにコードを修正する。


todo.rb

class Todo < ApplicationRecord

validates :title, presence: true
end


テストを実行する

以下のコマンドを実行してテストを行う。


console

rspec


下記のような結果が返ってくるはず。


console

Finished in 0.02788 seconds (files took 0.95229 seconds to load)

3 examples, 0 failures

テスト失敗がなくなっていることがわかる。


(2019/2/2 追記) Subjectを使ったRSpecの書き方

Subjectメソッドを使うと、もっと簡潔に書ける。


todo_spec.rb

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もやりやすいんじゃないかな。

終わり。