13

I've written a basic REST API using sinatra.

Does anyone know the best way to write tests for it? I would like to do so using Ruby.

I've done my initial testing using curl. But I'd like to do something more robust. This is my first API - is there anything specific I should be testing?

5
  • what's wrong with curl? You could write unit tests that run curl and check you get back what you expect - headers and body. Else you might consider something like watir.com ? Commented Jan 27, 2011 at 2:45
  • 2
    @lain: using Watir or curl is not unit test. Generally, it's a functional or integration testing. Commented Jan 27, 2011 at 2:56
  • 1
    Unit testing is testing the units of functionality from within the code, not from outside. Using curl or anything like it is outside the code looking in. We'd need to know more about what your web services are accomplishing to help you with unit tests. Commented Jan 27, 2011 at 3:04
  • I'm new to ruby and this is my first API. I'm open to all suggestions. What do you think is best? Thanks for your help so far. Commented Jan 27, 2011 at 3:09
  • You still haven't told us what your web application does. Commented Jan 27, 2011 at 3:15

5 Answers 5

6

The best way is a matter of opinion :) Personally, I like simple and clean. With tools like minitest, Watir and rest-client, you can put together a very simple test of both your REST interface as well as testing your web service through actual browsers (all major browsers are supported).

#!/usr/bin/ruby
#
# Requires that you have installed the following gem packages: 
# json, minitest, watir, watir-webdrive, rest-client
# To use Chrome, you need to install chromedriver on your path

require 'rubygems'
require 'rest-client'  
require 'json'
require 'pp'
require 'minitest/autorun'
require 'watir'
require 'watir-webdriver'

class TestReportSystem < MiniTest::Unit::TestCase
   def setup
      @browser = Watir::Browser.new :chrome # Defaults to firefox. Can do Safari and IE too.
      # Log in here.....
   end

   def teardown
      @browser.close
   end

   def test_report_lists   # For minitest, the method names need to start with test
      response = RestClient.get 'http://localhost:8080/reporter/reports/getReportList'
      assert_equal response.code,200
      parsed = JSON.parse response.to_str
      assert_equal parsed.length, 3 # There are 3 reports available on the test server
   end

   def test_on_browser
      @browser.goto 'http://localhost:8080/reporter/exampleReport/simple/genReport?month=Aug&year=2012'
      assert(@browser.text.include?('Report for Aug 2012'))
   end
end

Run the test cases by simply executing the script. There are many other testing systems and REST clients for Ruby which can be put to work in a similar way.

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

Comments

4

You might have a look at this approach http://anthonyeden.com/2013/07/10/testing-rest-apis-with-cucumber-and-rack.html

although many might say that using Cucumber is really more application or Acceptance testing and not unit testing, it does contain an approach to creating the HTTP headers and forming the http request, which I'm guessing might be where you are stuck?

Personally I don't have a problem with that since if you are truely going to unit test the API, you'd likely have to mock any units of code the api might be talking with (e.g. however you are persisting the data)

Seeing as I'm a QA guy not a dev, I'd be perfectly happy with using cucumber and testing it at that level, but I also greatly appreciate it when devs unit test, so while you might use rSpec instead of Cuke, perhaps the tip towards 'rack test' will be useful to what you are trying to accomplish.

3 Comments

That link is currently dead, it returns a 404
Yeah looks like his wordpress site got hacked and he's setting up a new home anthonyeden.com at this point you'd likely have to try and contact him or try using one of the internet time machines to see what that site looked like around the time I posted the response above.
corrected the link. some other well meaning person tried to make the edit, but idiot reviewers apparently thought it was too small of a change. personally correcting a not-working link into a working link does not seem small to me..
3

You can try using airborne which is a framework written for just this purpose:

https://github.com/brooklynDev/airborne

You can test against either a live API, or against a Sinatra, Grape, Rails application.

Comments

1

I would use fakeweb gem to do unit testing with web services.

2 Comments

This is not unit testing. Like Chamnap said above, it's integration testing.
No, I think it is a unit test, since it intercepts with every http request and send back the mock data we specified.
1

I would suggest client-api gem - it has loads of useful features specific to api automation which is easy to use and to maintain scripts.

https://github.com/prashanth-sams/client-api

Interestingly, this gem binds an api automation framework within itself. So, you don't even need a framework setup.

Key Features of client-api library:

  • Custom Header, URL, and Timeout support
  • URL query string customization
  • Datatype and key-pair value validation
  • Single key-pair response validation
  • Multi key-pair response validation
  • JSON response schema validation
  • JSON response content validation
  • JSON response size validation
  • JSON response is empty? validation
  • JSON response has specific key? validation
  • JSON response array-list sorting validation (descending, ascending)
  • Response headers validation
  • JSON template as body and schema
  • Support to store JSON responses of each tests for the current run
  • Logs support for debug
  • Custom logs remover
  • Auto-handle SSL for http(s) schemes

Example specs: https://github.com/prashanth-sams/client-api/tree/master/spec/client


Add this config snippet in the spec_helper.rb file:

ClientApi.configure do |config|
  config.base_url = 'https://reqres.in'
  config.headers = {'Content-Type' => 'application/json', 'Accept' => 'application/json'}
  config.basic_auth = {'Username' => '[email protected]', 'Password' => 'myp@ssw0rd'}
  config.json_output = {'Dirname' => './output', 'Filename' => 'test'}
  config.time_out = 10  # in secs
  config.logger = {'Dirname' => './logs', 'Filename' => 'test', 'StoreFilesCount' => 2}
end

RSpec test scenarios look like,

api = ClientApi::Api.new
it "GET request" do  
  api.get('/api/users')
  expect(api.status).to eq(200)
  expect(api.message).to eq('OK')
end

it "POST request" do
  api.post('/api/users', {"name": "prashanth sams"})
  expect(api.status).to eq(201)
end

Note: This is an active project handling issues and new features based on user requirements

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.