7
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

rspecのmockでつまづいた話

Last updated at Posted at 2018-11-06

この記事で書くこと

rspec-railsでmockを使用してテストする方法をまとめました。ただメソッドなどを紹介するというよりは、対象のコードがいて、それをテストするといった少しだけ実践的な方法で紹介します。

使用したコード

今回はcontroller specを使用します。(現在は、request specに移行することが推奨されているみたいです。)
テスト対象とテストコードは以下になります!

① テスト対象のコード。

app/controller/users_controller.rb
・・・
def create
    data = request.body.string
    user = User.new
    if user.change_allelgy_status(data) == 0 then
      render nothing: true, status: 200
    elsif 
      render nothing: true, status: 400
    end
 end
・・・

② テストコード。

spec/controllers/users_controller_spec.rb
require 'rails_helper'

RSpec.describe UsersController, type: :controller do

  describe "POST #create" do
    context "when the allergy status change process is successful" do
      it "has 200 status code." do
        user = instance_double(User)
        allow(User).to receive(:new).and_return(user)
        allow(user).to receive(:change_allelgy_status).and_return(0)
        post :create
        expect(response).to have_http_status(200)
      end
    end
  end
end

解説

1. インスタンスmockの作成

user = instance_double(User)

Userクラスのインスタンスmockを作成しています。これを作成することで、user.change_allelgy_statusのようなインスタンスメソッドをmockから呼び出すことができます。
また、似たような処理にUser = class_double(User)がありますが、これはUser.newのようにクラスメソッドmockから呼び出したい時に使用します。

2. スタブの作成

今回、個人的に1番ハマった処理です。まず、上手くいったコードからご紹介します。

allow(User).to receive(:new).and_return(user)
allow(user).to receive(:change_allelgy_status).and_return(0)

これは、user = User.newuser.change_allelgy_statusをそれぞれスタブにしたものです。

allow(User).to receive(:new).and_return(user)は、Userクラスのnewメソッドが呼ばれた時に、user(インスタンスmock)を返すという意味です。

user.change_allelgy_statusは、userインスタンスのchange_allelgy_statusメソッドが呼ばれた時に、0を返すという意味です。以下の分岐に入るように返り値を0にしています。

if user.change_allelgy_status(data) == 0 then
  render nothing: true, status: 200    # <= ここの分岐!!
elsif 

以上が正しいコードでした。それでは、次に僕がハマったパターンを紹介します。

allow(user).to receive(:change_allelgy_status).and_return(0)

はじめ、上記のコードだけ書いてテストしたところ、なぜかスタブのchange_allelgy_statusが呼ばれずに、実処理が実行されてしまいました。この原因は、おそらく下記だと思います。

app/controller/users_controller.rb
・・・
def create
    data = request.body.string
    user = User.new  
    # <= ここでuserインスタンスを作成しているため、次の処理で呼ばれる
    #        user.cahnge_allelgy_statusは、このuserインスタンスが使用される。
    if user.change_allelgy_status(data) == 0 then
      render nothing: true, status: 200
    elsif 
      render nothing: true, status: 400
    end
 end
・・・

従って、User.newから作成したuserインスタンスをスタブ化し、スタブ化されたインスタンスからchange_allelgy_statusを呼び出すことになりました。

allow(User).to receive(:new).and_return(user)
allow(user).to receive(:change_allelgy_status).and_return(0)

3. 期待値の確認

post :create
createアクションにpostリクエストを投げて、処理を開始します。

expect(response).to have_http_status(200)
postリクエストのレスポンスコードが200であることを確認しています。

まとめ

簡単ではありますが、rspecでmockを使用したテストをご紹介しました。実際に自分がつまづいた点も交えて記載したので、参考にしてもらえたら幸いです。

7
2
1

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
7
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?