2
3

More than 3 years have passed since last update.

【rails】RSpecによる単体テスト(コントローラ)

Posted at

準備

Gemrails-controller-testingをインストールする。

Gemfile
group :development, :test do
  # Call 'byebug' anywhere in the code to stop execution and get a debugger console
  ...
  gem 'rails-controller-testing' #追記 
end
terminal
$ bundle install

次のディレクトリを作成する。
 spec/controllers

次のファイルを作成する。
 spec/controllers/tweets_controller_spec.rb

spec/controllers/tweets_controller_spec.rb
require 'rails_helper'

describe TweetsController do

end

specファイルを特定してテストを実行する。

terminal
$ bundle exec rspec spec/controllers/tweets_controller_spec.rb

Finished in ~

0 examples, 0 failures

正常に実行できることを確認した。

テストコード

newアクション

spec/controllers/tweets_controller_spec.rb
require 'rails_helper'

describe TweetsController do
  # describe 'http method' #action do
  describe 'GET' #new do
    it 'new.html.erbに遷移すること' do
      get :new
      expect(response).to render_template :new
    end
  end
end
response

example内で行われるリクエストの後の遷移先のビューの情報を持つインスタンス。

render_templateマッチャ

引数にシンボル型のアクションを指定することで、そのアクションがリクエストされた時に自動的に遷移するビューを返す。

テストを実行する。

terminal
$ bundle exec rspec spec/controllers/tweets_controller_spec.rb

TweetsController
  GET #new
    new.html.erbに遷移すること

Finished in ~
1 example, 0 failures

editアクション

コントローラ確認

app/controllers/tweets_controller.rb
  def edit
    @tweet = Tweet.find(params[:id])
  end

editアクションでは、@tweetインスタンスを定義している。

spec/controllers/tweets_controller_spec.rb
require 'rails_helper'

describe TweetsController do
  # describe 'http method' #action do
  describe 'GET' #new do
    ...

  describe 'GET #edit' do
    it "@tweetに正しい値が入っていること" do
      # factory_botで定義するインスタンスを一時的にDBに登録して取得する
      # 登録したデータはテスト完了時に削除される
      tweet = create(:tweet)
      # 作成したインスタンスのidをセットする
      get :edit, params: { id: tweet }
      #editアクションで取得するtweetが、テストで作成したtweetと同じであることを確認する
      expect(assigns(:tweet)).to eq tweet
    end

    it "edit.html.erbに遷移すること" do
      tweet = create(:tweet)
      get :edit, params: { id: tweet }
      expect(response).to render_template :edit
    end
  end
end
assignsメソッド

コントローラのテスト時に、アクションで定義するインスタンス変数をテストするためのメソッド。
直前で定義したアクションの中で定義されるインスタンス変数を、シンボル型でとる。
@tweet -> :tweet)

factory_botでtweetインスタンスを定義する。

spec/factories/tweets.rb
FactoryBot.define do
  factory :tweet do
    text {"hello!"}
    image {"hoge.png"}
    # created_atをランダムに生成
    created_at { Faker::Time.between(from: DateTime.now - 2, to: DateTime.now ) }
    user
  end
end

登録日カラムにて利用するFakerの説明は最後に。

indexアクション

indexアクションを確認する。

app/controllers/tweets_controller.rb
  ...
  def index
    @tweets = Tweet.includes(:user).order("created_at DESC").page(params[:page]).per(5)
  end
  ...
spec/controllers/tweets_controller_spec.rb
describe 'GET #index' do
  it "@tweetに正しい値が入っていること"
    #tweetレコードを3つ保存して、変数tweetsにインスタンスに取得
    tweets = create_list(:tweet, 3)
    #indexアクションへの擬似的なリクエスト
    get :index
    # created_atを基準にして、降順にtweetsを並び替える処理
    expect(assigns(:tweets)).to match(tweets.sort{ |a, b| b.created_at <=> a.created_at })
  end
  it "index.html.erbに遷移すること"
    get :index
    expect(response).to render_template :index
  end
end
matchマッチャ

引数に配列クラスのインスタンスをとり、expectの引数と比較する。
配列の中身の順番までチェックする。

factory_botでのuserインスタンス定義する。

spec/factories/users.rb
FactoryBot.define do
  factory :user do
    nickname              {"abe"}
    # email                 {"kkk@gmail.com"}
    password              {"00000000"}
    password_confirmation {"00000000"}
    sequence(:email) {Faker::Internet.email}
  end
end
Faker

今回、tweetインスタンスを複数作ることになるが、emailの値が重複するとバリデーションによりエラーが起こる。
そのため、Fakerで動的にダミーデータを生成する。

Gemfile
group :test do
  ...
  gem 'faker', "~> 2.8"
end
terminal
$ bundle install

テストの実行

terminal
$ bundle exec rspec spec/controllers/tweets_controller_spec.rb  
2020-05-16 16:26:37 WARN Selenium [DEPRECATION] Selenium::WebDriver::Chrome#driver_path= is deprecated. Use Selenium::WebDriver::Chrome::Service#driver_path= instead.

TweetsController
  GET #new
    new.html.erbに遷移すること
  GET #edit
    @tweetに正しい値が入っていること
    edit.html.erbに遷移すること
  GET #index
    @tweetに正しい値が入っていること
    index.html.erbに遷移にすること

Finished in 0.7887 seconds (files took 3.68 seconds to load)
5 examples, 0 failures

予期する通り動作することを確認できた。

RSpec参考書籍

2
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
3