6

I'm putting together a JSON API which may or may not be built with Rails. I'd like to be able to verify that the JSON API is behaving as expected by testing it from a test client that only communicates via HTTP.

For example, the test client will send a request to a given URL on the test server, and then verify that the response is a JSON string equal to what is expected by the specs. The response may also be an HTTP response code such as a 401.

I'm currently running tests with QUnit and jQuery.ajax. It works, but I'm wondering if there's a better option. Has anyone else done something like this?

Thanks!

1
  • Usually I test apis as part of the codebase - this is for good reasons, like: the api codebase having tests for documentation; errors show you run the test suite after making a refactor; it's easier to track down issues with the tests; they run as part of continuous integration. Commented Nov 5, 2011 at 17:36

10 Answers 10

6

Any language with a decent HTTP library and a JSON library ought to do. Just pick your favorite language and testing framework and go for it. I'd probably use RSpec and Rack::Test, especially if the API will be implemented in Ruby, but tastes vary.

Edit: You mentioned you'd like to run the tests outside the server. If you're sure about that then use e.g. Net::HTTP instead of Rack::Test.

Sign up to request clarification or add additional context in comments.

2 Comments

We're trying to gather requirements as a series of tests before choosing a language or framework. We won't know what to look for in a framework before we have our tests/requirements.
good comment, totally on point. any test framework should easily support this. I'd also recommend having the tests live in a plugin that can be included on the API codebase so you can more easily run them when you've only checked out the API codebase.
3

Usually API is regular controllers/actions. So you can test this actions as regular controller inside of server app. Thats like i test my API actions:

describe Api::AccountsController do
  describe "GET :index" do
    it "should be success" do
      do_get
      response.should be_success
    end

    it "should return list of accounts" do
      5.times{ Factory :account }
      do_get
      JSON.parse(response.body).size.should == 5
    end

    it "should return id, name and description of each account" do
      account = Factory :account
      do_get
      result = JSON.parse(response.body).first
      result['account']['id'].should == account.id
      result['account']['name'].should == account.name
      result['account']['description'].should == account.description
    end

    def do_get
      get :index, :format => :json
    end
  end
end

1 Comment

The solution needs to communicate over HTTP and be server framework agnostic.
2
+50

Check out the python requests library. I've used it for just such a purpose and it is awesome.

http://docs.python-requests.org/en/latest/index.html

Comments

1

I've worked on a JS API for Rails and built a whole set of tests using QUnit and jQuery. I was quite happy with the end result, my aim was to test the API thoroughly and this combination of tools was everything I needed.

I've been working on a new project that uses Jasmine, its a bit more descriptive in the way you write tests (which makes the Business Analysts happy) but the end result was much the same as QUnit.

Comments

0

It seems like some have found success with cucumber (checkout this similar question)

What is the recommended method of testing a JSON client-server api?

Comments

0

I agree with @mpartel completely.

You'll presumably want a set of unit tests (without the complexity of HTTP) to test the logic of your implementation. Once you go down that route, you'll find that there will be a benefit in writing the tests in the same language.

For example, you if you write it in Rails (and use Rack::Test), you'll also be able to unit test lots of the cases in a simpler Test::Unit (or RSpec) environment.

1 Comment

We're trying to gather requirements as a series of tests before choosing a language or framework. We won't know what to look for in a framework before we have our tests/requirements.
0

One way you can do this is controller tests using rspec

describe PersonApiController 
  # GET /person/1.json
  it "should respond with a person" do 
     person = Person.create(:name => "scott")
     get :show, :id => person.id, :format => 'json'
     response.should be_success
     response.body.should have_selector('name', :content => person.name)
  end
end 

If you want to get even fancier, you can share a api client via a plugin/gem between your client code and your server code and then initialize it using the json like

person_client = PersonClient.new(response.body)
person_client.name.should eql 'scott'

8 Comments

Controller tests suck. Use Cucumber instead.
For user-facing stuff, no. Controller tests demonstrably do the wrong things and should be entirely avoided. For API stuff, it's borderline. Very little in software development is a matter of opinion.
Note my qualification. For APIs, it's borderline.
We may not be using Rails. The solution needs to communicate over HTTP and be server framework agnostic.
Cucumber's an easy install. Test::Unit is the wrong tool for this situation (or almost any other) because it encourages the testing of implementation instead of behavior.
|
0

Just write some specs with Cucumber and/or RSpec to connect to your app and test the output. No need to drag JQuery into it.

2 Comments

Do you have any examples of this?
What do you need examples of? Just use Capybara or Rack::Test to visit or post to the appropriate URL, then call JSON.parse page.driver.response.body or something like that and test the result.
0

http://www.soapui.org/

a functional testing tool.

Comments

0

I did it! This is how to do it with vanilla Rails. Notice the different accept mime type. You may parse the JSON if you wish. Comparing as strings was sufficient.

  test "vote comment up" do
    # @request.headers["Content-Type"] = "application/json"
    @request.headers["Accept"] = "application/javascript"
    post :up, {post_id: 1, id: 1}, {user_id: 5}
    assert_response :success
    assert_equal @response.body, '{"error":true,"errorPath":"/users/5/balance","userVotes":1,"totalVotes":0}'
  end

If you want to test during development, I use Advanced Rest Client Chrome Extension.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.