リクエスト spec を書こう - satococoa/api-tutorial GitHub Wiki

リクエスト spec とは

主に API のテストに使われ、「このパスにこのパラメータ、データを持ってアクセスするとこういう出力が得られる」という一連のアプリケーションの特定のパスの入出力を試験します。

投稿一覧の取得を前回作りましたので、それをテストしてみたいと思います。 テストの中身は以下のような感じです。

  1. 投稿が 10 個あるとき
  2. 投稿一覧のパスに GET で json をリクエストしたとき
  3. ステータスコードは 200 が返る
  4. 10 個の投稿の内容 (title, name, body) が json で返ってくる

以下のコマンドで request spec のひな形を generate してください。

rails generate integration_test api/v1/posts

生成された spec/requests/api/v1/api_v1_posts_spec.rb を以下のように編集します。

require 'spec_helper'

describe "Api::V1::Posts" do
  describe "GET /api/v1/posts" do
    before do
      10.times { FactoryGirl.create(:post) }
    end

    it 'レスポンスコードは 200' do
      get api_v1_posts_path, format: :json
      expect(response.status).to eq(200)
    end

    it '10個の投稿が返る' do
      get api_v1_posts_path, format: :json
      json = JSON.parse(response.body)
      expect(json.count).to eq(10)
    end

    it '各要素は title, name, body 属性を持つ' do
      get api_v1_posts_path, format: :json
      json = JSON.parse(response.body)
      json.each do |data|
        keys = data.keys
        expect(keys).to match_array(['title', 'name', 'body'])
      end
    end
  end
end

例)

it '必要な属性がある' do
      get api_v1_posts_path, format: :json
      json = JSON.parse(response.body)
      json.each do |data|
        expect(data.keys).to match_array(['title', 'name', 'body'])

        #expect(data['title']).not_to eq('')
        #expect(data['body']).not_to eq('')
        #expect(data['name']).not_to eq('')

        #expect(data['title'].nil?).not_to be_true
        #expect(data['body'].nil?).not_to be_true
        #expect(data['name'].nil?).not_to be_true
      end
    end

テストコードを rake spec コマンドで実行してください。すべてのテストがパスすれば成功です。

リファクタリング

実装コードは十分すぎるほどシンプルなので、テストコードの方をリファクタリングしてみます。 spec/requests/api/v1/api_v1_posts_spec.rb は以下のようになりました。

require 'spec_helper'

describe "Api::V1::Posts" do
  describe "GET /api/v1/posts" do
    context '10 個の投稿があるとき' do
      subject(:json) { JSON.parse(response.body) }

      before do
        10.times { FactoryGirl.create(:post) }
        get api_v1_posts_path, format: :json
      end

      it "レスポンスコードは 200" do
        expect(response.status).to eq(200)
      end

      it "10 個の投稿が返る" do
        expect(json).to have(10).posts
      end

      it "各要素は title, name, body 属性を持つ" do
        json.each do |data|
          expect(data.keys).to match_array(['title', 'name', 'body'])
        end
      end
    end
  end
end

注意

本来は前回の Api::V1::PostsController#index を実装する前にこの spec から書くべきではありましたが、わかりやすくするためにこの順序で書きました。