Tuesday, 23 December 2014

12 Tips of Christmas - 12 Testing your API

12 Tips of Christmas - 12 Testing your API

In our final tip, we're going to take a look at testing our API, which now looks like this

module API
  module V1
    class Posts < Grape::API
      version 'v1'
      format :json

      resource :posts do
        desc "Return 10 most recent posts"

        get do
          posts = Post.most_recent.limit(10)
          present :posts, posts, with: API::V1::Entities::Post
        end

        desc 'Find a specific post'
        params do
          requires :id, type: Integer, desc: "The ID of the post"
        end
        get ':id' do
          post = Post.find(params[:id)
          present :post, post, with: API::V1::Entities::Post              
        end
      end

    end
  end
end

To begin, we want to ensure that our API returns the data we expect it to

# spec/api/v1/post_spec.rb

describe API::V1::posts do
  describe "GET /api/v1/posts" do
    it "returns an empty array of statuses" do
      get "/api/v1/posts"
      expect(response.status).to eq(200)
      expect(JSON.parse(response.body)).to eq({"posts"=>[]})
    end

    it "filters based on names" do
      expected_post = create(:post, content: "Foobar")
      unexpected_post = create(:post, content: "Baz")
      get "/api/v1/posts?content=Foobar"

      expect(response.status).to eq(200)
      expect(JSON.parse(response.body)).to eq({"posts"=>[{"id"=>expected_post.id,
                                                           "content"=> expected_post.content, "created_at"=>"#{expected_post.created_at}"
                                                           }]})
    end
    it "filters based on location id" do
      expected_post = create(:post, content: "Foobar")
      unexpected_post = create(:post, content: "Baz")
      get "/api/v1/posts?place_id=Quas"

      expect(response.status).to eq(200)
      expect(JSON.parse(response.body)).to eq({"posts"=>[{"id"=>expected_post.id,
                                                           "content"=> expected_post.content, "created_at"=>"#{expected_post.created_at}"
                                                          }]})
    end
  end
end

As you can see these function very similar to a request spec and are implemented accordingly. The utilisation of the JSON.parse ensures our content that is exposed matched what we expect.

A simpler version for this is using airborne a Gem designed to not only verify the type of content we return, but the content itself, for example:

it 'should validate types' do
  expected_post = create(:post, content: "Foobar")
  unexpected_post = create(:post, content: "Baz")
  get "/api/v1/posts?content=Foobar"
  expect_json({"posts"=>[{"id"=>expected_post.id,"content"=> expected_post.content, "created_at"=>"#{expected_post.created_at}"}]})
  expect_json_types({id: :integer)
end

So now you have no excuse for not testing your API!

No comments:

Post a Comment