はじめに
これからRSpecを導入しようとされている方の中で、
- テストに対する抵抗感をなくしたい
- まずは簡単なテストの書き方を知りたい
という方向けに書きました。
RSpecの超基本文法とそれを使ったテストの例を以下4つの視点で1つずつ掲載しています。
- Model
- Controller
- View
- Routing
参考になれば幸いです。
【参考にさせて頂いた記事】
使えるRSpec入門・その1「RSpecの基本的な構文や便利な機能を理解する」 - Qiita
使えるRSpec入門・その2「使用頻度の高いマッチャを使いこなす」 - Qiita
使えるRSpec入門・その4「どんなブラウザ操作も自由自在!逆引きCapybara大辞典」 - Qiita
Ruby on Rails のテストフレームワーク RSpec 事始め - Qiita
この記事が役に立つ方
- RSpecでテストを書いたことがない方
この記事のメリット
- RSpecへの抵抗感がなくなる
環境
- OS: macOS Catalina 10.15.1
- シェル: zsh
- Ruby: 2.6.5
- Rails: 5.2.3
- RSpec: 3.9.0
【事前準備】
今回はscaffoldを使ったアプリケーションを例にしますので、3ステップで事前準備をしておきましょう。
1. scaffoldでアプリケーションを作成しておく
$ rails g scaffold user name:string email:string
2. RSpecをインストールし、テスト用ファイルを作成する
group :development, :test do
gem `rspec-rails`
end
↓
$ bundle install
↓
$ rails g rspec:install
3.テストの実行方法の把握
$ rspec
上記で全テストが走りますので、テストを書いたら走らせてみましょう。
次に基本文法を見ていきます。
基本文法
require 'rails_helper'
RSpec.describe テスト対象, テストの種類 do
describe 'テスト対象' do
it '期待する内容を言葉で書く' do
期待する動作をコードで書く
end
end
end
※実際は他にcontext
、before
なども使いますが、本記事では超シンプルなテストを例にします。
基本文法だけ見てもよく分からないと思いますので、さっと目を通して以下具体例に移りましょう。
具体例
MVC+Routingそれぞれに対し、1つずつ超シンプルなテストを書いて試していきます。
それぞれ、動作するテストのみ記載していますので、自分でいじってみて失敗するかどうかも確認するほうが良いと思います。
1.Model
バリデーションが正しく動作するかをテストしたい
Userモデルに以下のようなバリデーションがかかっていて、それをテストしたいとします。
class User < ApplicationRecord
with_options presence: true do
validates :name
validates :email
end
end
では、テストを書いてみましょう。
最初に以下コマンドを実行し、テストの雛形を作成しましょう。
$ rails g rspec:models user
spec/models/user_spec.rb
が出来ているはずなので、以下のように記述して下さい。
require 'rails_helper'
RSpec.describe User, type: :model do
describe 'Userモデルのバリデーションテスト' do
it 'nameとemailに値があれば有効' do
user = User.new(
name: "name",
email: "sample@example.com"
)
expect(user).to be_valid
end
end
end
【解説】
User, type: :model
でUser Modelのテストであることを明示。
user
に適当な名前とメールアドレスを指定してUserモデルから新規インスタンスを作成し、それをbe_valid
というマッチャで有効かどうかを判定しています。
2.Controller
indexアクションで正常にページが表示されるかテストしたい
正常にページが表示されるかはHTTPレスポンスが200であると言い換えることが出来ます。
テストを書いてみましょう。
まず先程と同様、以下コマンドを実行します。
$ rails g rspec:request users
**「あれ?request? controllerじゃないの?」**と思いますよね。
実は、Rails5以降はcontroller_specが非推奨となっています。
controller_specでも書けるのですが、controller関連はrequest_specで記載するのが良いようです。
詳細は下記リンクより。
では戻ります。
先程のコマンドで
spec/request/users_spec.rb
が出来ているので以下のように記述して下さい。
require 'rails_helper'
RSpec.describe "Users", type: :request do
describe "GET /users" do
it "HTTPレスポンスが200になる" do
get users_path
expect(response).to have_http_status(200)
end
end
end
【解説】
"Users", type: :request
と指定することでUsersのrequest_specであることを明示。
getリクエストでusers_path
(/users)を指定し、それに対するHTTPレスポンスがresponse
に入ります。
そのresponse
に対してhave_http_status
というマッチャで200
と等しいかを確認しています。
3.View
<h1>
タグ内が正しく表示されるかをテストする
<h1>Users</h1>
index/html/erb
にはこんなh1
タグが記載されています。
このh1
タグ内に表示されている内容が正しく表示されているかをテストしてみましょう。
まずはテスト用のファイルを以下のように作成します。
$ rails g rspec:view users index
spec/views/users/index.html.erb_spec.rb
が出来ているので、以下のように記述して下さい。
require 'rails_helper'
RSpec.describe "users/index", type: :view do
describe 'index.html.erbのテスト' do
it 'h1タグ内にUsersが表示されているかどうか' do
visit users_path
expect(page).to have_selector('h1', text: 'Users')
end
end
end
【解説】
users/index
のview
のテストであることを最初に明示。
visit
の後にusers_path
を指定することでindex.html.erb
にアクセス。
expect(page)
で今いるページを明示、have_selector
というマッチャで'h1'にUsers
が表示されているかをテストしています。
...
※実は上記テストはうまくいきません。
騙したようで申し訳ありません。テストを実行したら、
NoMethodError: undefined method 'visit'
というエラーが出ませんでしたか?
実は自分もここで手間取りました。
ググるとかなり沢山記事が出てくるので、良くあるエラーなんだと思います。
原因はgemcapybara
がRSpecに読み込まれていないことです。
visit
はcapybara
の中で定義されている**DSL(ドメイン指定言語)**のため、読み込むために設定を追加しなければいけません。
spec/spec_helper.rb
を開いて以下のように2行追記して下さい。
...略
require 'capybara/rspec' # ここに追記
RSpec.configure do |config|
config.include Capybara::DSL # ここに追記
...略
end
この設定で読み込まれるCapybara::DSL
で定義されているDSL一覧は以下で確認することができます。
もし他にNoMethodError
が出たら参考にしてみるのも良いかもしれません。
うまくいったら次に進みましょう。
4.Routing
ページのルーティングが正しいかをテストする
最後はルーティングです。
createアクションに対してルーティングがうまくいっているかテストをしてみましょう。
テスト用のファイルはジェネレータを使わなくても作成出来るので、
今回は、手入力でファイルを作成します。
spec/routing/users_routing_spec.rb
を新規作成し、以下のように記述して下さい。
require 'rails_helper'
RSpec.describe "routes for Users", type: :routing do
describe 'ルーティングのテスト' do
it 'createアクションのルーティング' do
expect(post("/users")).to route_to("users#create")
end
end
end
【解説】
Users
のrouting
についてのテストであることを明示。
/users
にPOSTしたら users
コントローラーのcreate
アクションが動くことをテストしています。
おわりに
いかがでしたでしょうか?
超基本的な内容ではありますが、書くことに対しての苦手意識が少しで減ればいいなと思います。
私も書きながら調べていましたが、検索でヒットする内容には古い情報が多く、苦労しました。
今後も以下最新情報を参照しつつ勉強していこうと思います
RSpec Rails 3-9 - RSpec Rails - RSpec - Relish
参考にさせて頂いたサイト(いつもありがとうございます)
使えるRSpec入門・その1「RSpecの基本的な構文や便利な機能を理解する」 - Qiita
使えるRSpec入門・その2「使用頻度の高いマッチャを使いこなす」 - Qiita
使えるRSpec入門・その4「どんなブラウザ操作も自由自在!逆引きCapybara大辞典」 - Qiita
Ruby on Rails のテストフレームワーク RSpec 事始め - Qiita
全国のSeleniumer必読 - Qiita
undefined method `visit’ when using RSpec and Capybara in rails
capybara cheat sheet · GitHub