1. ホーム
  2. Ruby on Rails
  3. Rails5でRSpec入門

Rails5でRSpec入門

目次

  1. はじめに
  2. RSpecとは
  3. RSpecの設定
  4. RSpecでテストを実行する
  5. RSpecのテスト自動化
  6. まとめ

はじめに

システム開発にはテストが欠かせません。
Ruby on Railsではデフォルトのテスト機能もありますが、より便利で最も多くのRubiestが使用するテストフレームワーク、RSpecの導入方法や簡単な使い方をご紹介します。

今回使用する環境

  • Ruby: 2.3.1
  • Ruby on Rails: 5.1.4
  • RSpec(rspec-rails): 3.6.0

RSpecとは


RSpecはテストフレームワークです。ソースコードが正しい動作をしているか、テストコードを書くことでその確認をすることができます。

公式サイトを見るとこのように書かれています。

Behaviour Driven Development for Ruby.
Making TDD Productive and Fun.

ここで書かれている「Behaviour Driven Development」と「TDD」とは何者でしょうか。
簡単に解説します。

TDDとは

TDDとは、「Test Driven Development」の略です。

通常のウォーターフォール型のシステム開発においては、このような開発フローが一般的です。

  1. 出来るだけ完璧なソースコードを書いて
  2. テストコードを書いて
  3. テストをする、ダメなら1に戻る

TDDでは、このようなフローとなります。

  1. テストコードを書いて
  2. テストを通るソースコードを出来るだけ早く書いて
  3. テストをする、通ったら2に戻りコードを精錬させる(リファクタリング)

TDDを使用することで、バグが早期段階でわかるようになるので、工数の削減や最終的なバグの数が少なくなることがメリットです。

POINT!!

メリットばかりではなく、TDDにはデメリットや失敗事例も多くあります。最も要因として大きいことが、開発者がTDDを理解し慣れるまでに時間がかかるということです。
どうしても急ぐときにテストコードを書くのが難しくなり、そのまま書かない(開発→最後にテストという流れ)に戻ってしまうケースもよく耳にします。

Behaviour Driven Development、BDDについては振る舞い駆動開発、ビヘイビア駆動開発など訳されます。
TDDをより読みやすい(理解しやすい)テストコード化したもので、「何を実現したいのか」など振る舞いを書くものとなります。

RSpecの設定

まずGemfileに以下の設定をしましょう。

group :development, :test do
  gem 'rspec-rails', '~> 3.5'
end

そしてbundle install を実行します。
rspec-railsがインストールされたら、初期化を行います。

rails generate rspec:install

実行結果がこちらです。

create  .rspec
create  spec
create  spec/spec_helper.rb
create  spec/rails_helper.rb

それぞれ役割を見ていきましょう。
.rspecファイル→読み込むヘルパーやドキュメントフォーマットなどを設定するファイル。
specディレクトリ→テストファイルを格納するディレクトリ
spec/spec_helper.rb→あくまでもRSpecに関する設定が書かれているヘルパーファイル
spec/rails_helper.rb→Rails側の設定用ヘルパーファイル。

POINT!!

以前ヘルパーは spec_helper.rb のみ作られていましたが、Rspecのバージョン3以降からrails_helper.rbが作られるようになっています。 確かにrails_helper.rb には ActiveRecord の設定や fixture(テストの事前設定)のRails用のパスなどが書かれていますが、spec_helper.rb にはそのようなRails関係の設定は一切記述されていません。

RSpecでテストを実行する

一旦この状態でRSpecでテストを実行させてみましょう。
bundle exec rspec

するとこのようなメッセージが表示されます。

No examples found.
Finished in 0.00038 seconds (files took 0.3511 seconds to load)
0 examples, 0 failures

見方としては、examples がテスト、failures がその失敗と考えてください。
つまり、0件のテストを実行し0件失敗したよというメッセージです。
(何も書いていないので当然です。)

では、実際にテストを書いてみましょう。
まずmodelを追加してみます。
rails g model User name:string

するとこのような実行結果が出ます。

Running via Spring preloader in process 23586
      invoke  active_record
      create    db/migrate/20170726000503_create_users.rb
      create    app/models/user.rb
      invoke    rspec
      create      spec/models/user_spec.rb

spec/models/user_spec.rb が自動的に作られたことがわかると思います。
rake db:migrate コマンドでmigrationをしておきましょう。

もちろん既存のコードにもテストを適用することができます。
rails g rspec:model user
このようにspec:controller や spec:view などテストを作りたい対象を指定することでspecファイルが作られます。
spec/models/user_spec.rb

 

では、テストを書いてみましょう。
ここではUserのnameは必須という仕様で、 nameの存在チェックに関するバリデーションが正しく動作すること が期待する動作とします。

まず、先程の順番に沿って「1. テストコードを書いて」からはじめましょう。

spec/models/user_spec.rb

require 'rails_helper'

describe User do  # 何のテストをするのか、対象を書く
  it 'is not be valid without name' do # 期待する動作説明を書く
    user = User.new(name: '')
    expect(user).not_to be_valid # 動作をテストする部分
  end
end

解説ですが、user には name が空っぽのデータが入っています。
ここで期待することは「nameの存在チェックに関するバリデーションが正しく動作すること」です。
expect(user).not_to be_valid で「userはバリデーションエラーとなっていること」をテストしています。

では、ここでテストを実行しましょう。
bundle exec rspec

F

Failures:

  1) User is not be valid
     Failure/Error: expect(user).not_to be_valid
       expected #<User id: nil, name: "", created_at: nil, updated_at: nil> not to be valid
     # ./spec/models/user_spec.rb:6:in `block (2 levels) in <top (required)>'

Finished in 0.05656 seconds (files took 5.15 seconds to load)
1 example, 1 failure

Failed examples:

rspec ./spec/models/user_spec.rb:4 # User is not be valid

メッセージでお分かりになるように、テストに失敗しました。
「nameの存在チェックに関するバリデーション」が実装されていないので当然ですよね。

では、次のステップの「2. テストを通るソースコードを出来るだけ早く書いて」を実施しましょう。

「nameの存在チェックに関するバリデーション」を実装してテストすれば、テストは成功するはずです。
models/user.rb

class User < ApplicationRecord
  validates :name, presence: true
end

存在チェックを実装したので次のステップに進みます。
「3. テストをする、通ったら2に戻りコードを精錬させる(リファクタリング)」

ではもう一度テストをしてみましょう。
bundle exec rspec

.

Finished in 0.03041 seconds (files took 4.85 seconds to load)
1 example, 0 failures

failuresが0になり、テストに成功しました!
これで最低限の仕様を満たすコードが実現できました。
ここからテストを成功した状態でコードを精錬させていく(リファクタリング)をしていくことがTDDの簡単な流れです。

RSpecのテスト自動化

毎回 rspec コマンドを打つのは大変ですよね。
そんなときに便利なのはguard というgemです。
gem 'guard-rspec', require: false
をGemfileに記載し、bundle install しましょう。

このコマンドで設定ファイルが作られます。
bundle exec guard init rspec

Guardfile というファイルが出来ているので、そちらに監視対象のファイルなど設定をすることができます。

そして bundle exec guard でguardによる監視がスタートします。
あとは監視ファイルにあるspecファイルを修正することでテストが自動で実行されます。

更に terminal-notifier-guard などの通知Gemを導入することで、ますます便利になるはずです。

まとめ

RSpecを導入することで、口語のような読みやすくわかりやすいテストを書くことができます。
またTDDのサイクルを回すことで、より短期間に品質が担保されたコードを実現することができます。(慣れは必要ですが…)

投稿者プロフィール

eishis
eishis
SIerやスタートアップ、フリーランスを経て2016年11月にeishis, Inc.を設立。
マーケター・ディレクター・エンジニアなど何でも屋。
COBOLからReactまで色んなことやります。