Ruby on Railsで、RSpec を使ってコントローラのテストをしたテストコードの例を載せておきます。

環境は、Ruby on Rails3、Ruby1.9.2 を使っています。RSpec の使い方の参考になれば幸いです。

RSpec で Controller のテストを書いてみた

Ruby on Rails3, Ruby1.9.2 で Controller クラスの RSpec を書いてみました。

Controller でテストしたのは次の3点です。

  1. ルーティングが合っているか
  2. 処理が通って 200 OK を返すか
  3. 処理が通って期待通りの結果(Blog が保存されることによって count がひとつ増える)になっているか
# coding: UTF-8
require 'spec_helper'
 
describe BlogsController do
  describe "GET /blogs/:id" do
    describe :routes do
      subject { {:get => "/blogs/1"} }
      it { should route_to(controller: "blogs", action: "show", id: "1") }
    end
 
    before { get :show, :id => "1" }
 
    describe :response do
      subject { response }
      it { should be_success }
    end
  end
 
  describe "POST /blogs" do
    def do_post
      post :create, :article => "xxx"
    end
 
    describe :routes do
      subject { {:post => "/blogs"} }
      it { should route_to(controller: "blogs", action: "create") }
    end
    
    before { do_post }
 
    describe :response do
      subject { response }
      it { should be_success }
    end
 
    describe :blog, :save do
      before { controller.stub!(:authenticate).and_return(true) }
      subject { expect { do_post } }
      it { should change(Blog, :count).by(1) }
    end
  end
end

ソースコード解説

ルーティングのテスト

describe にはテスト対象を記述しています。コントローラのテストなので、それぞれのルーティングごとにテストを記述しています。

:routes でテストしているのは、期待したリクエスト URL が期待したコントローラの呼び出しになっているかどうかです。

subject にはこのテストの実際のテスト対象で、:routes では、ルーティングリクエストを記述しています。続く it で実際に期待する処理を書いています。should にレシーバを記述しない場合には subject の中身がレシーバになります。

route_to で期待するルーティングを記述してルーティングのテストをしています。

コントローラの処理が正常に終了するかどうかのテスト

response オブジェクトを subject にして success を返すかどうかをテストしています。

コントローラが期待した処理を行ったかどうかをテストする

コントローラが期待した処理を行ったことを確認するには、二つやり方があると思っています。

ひとつは、コントローラをブラックボックスにして、コントローラを通る前の状態とコントローラを通った後の状態を比較するやり方

もうひとつは、コントローラをホワイトボックスにして、モックオブジェクを使って should_receive や should_not_receive で期待した処理を通ったかどうかを確認するやり方

今回は、一つ目のやり方でテストをしています。これは、should_receive や should_not_receive を使ってテストしてしまうと、リファクタリングでメソッド名を変更した際にテストも直さなければならないからです。

個人的には、コントローラのテストでは should_receive や should_not_receive はあまり使わず、実際にデータベースに書き込みを行ってテストをするのが良いと思っています。(Rails ではテスト用のDBは別に用意されますので)

なお、before では controller.stub! を使って、コントローラに認証が必要な場合に認証を素通りする例を記述しています。

参考