Awesome
rack-test-rest
is an extension to rack-test
that when combined with
Test::Unit
simplifies the process of unit testing properly
designed RESTful API's.
Installation
$ gem install rack-test-rest
Use
rack-test-rest
extends rack-test
with a set of higher-level methods that
perform CRUD operations against resources through a RESTful API that conforms
to best practices and validates that they respond correctly.
It's designed to be mixed into a subclass of Test::Unit::Testcase
that is testing a specific resource e.g.:
class GaugeTest < Test::Unit::TestCase
include Rack::Test::Methods
include Rack::Test::Rest
def setup
@rack_test_rest = {
#:debug => true,
:root_uri => "/v1/metrics",
:resource => "gauges",
:extension => ".json" #other possibilities ".xml", "_json",".html", etc
}
end
def test_create
create_resource(:name => "foo")
create_resource(:code => 422, :name => "foo")
end
def test_read
create_resource(:name => "foo")
gauge = read_resource(:id => "foo")
assert gauge['name'] == "foo"
end
def test_update
create_resource(:name => "foo", :description => "bar")
update_resource(:id => "foo", :description => "baz")
gauge = read_resource(:id => "foo")
assert gauge['description'] == "baz"
end
def test_delete
create_resource(:name => "foo")
delete_resource(:id => "foo")
read_resource(:code => 404, :id => "foo")
end
rack-test-rest
exploits convention over configuration to minimize the amount of work
required to test any particular resource. You need only specify :root_uri
and :resource
in your test setup (through the @rack_test_rest
instance variable). These are combined
to create either the URI for creating/indexing resources or the URI for a particular resource:
:root_uri + '/' + :resource + :extension
:root_uri + '/' + :resource + '/' + params[:id].to_s + :extension
Currently JSON is the only supported response Content-Type.
create_resource(params={})
Performs a POST to with any specified parameters to :root_uri/:resource:extension
and ensures that it returns 201
. Returns the string value found in the response's
Location
header.
read_resource(params={})
Performs a GET with any specified parameters and validates that it returns 200
.
If :id
is specified the GET is performed against a singular resource i.e.
:root_uri/:resource/:id:extension
. In the absence of :id
the GET is performed
as an index operation against :root_uri/:resource:extension
. Returns parsed
JSON of the response body on a 200
.
update_resource(params={})
Requires an :id parameter. Performs a PUT against :root_uri/:resource/:id:extension
with any other specified parameters and asserts that it returns 204
.
delete_resource(params={})
Requires an :id parameter. Performs a DELETE against :root_uri/:resource/:id:extension
and asserts that it returns 204
.
Testing invalid input
Any of the CRUD operations can be altered to check that invalid input is properly
detected and returns the correct error code by specifying :code
as a parameter
e.g.
create_resource(:code => 422, :name => duplicate_name)
read_resource(:code => 404, :id => invalid_id)
Debugging
The point of unit tests is to surface and fix defects and/or regressions in your code
in the lab rather than than in production. When your tests fail you can include
:debug => true
to instruct rack-rest-test
to verbosely log to STDOUT the individual
HTTP requests it's performing and the results of each.
Pagination
rack-test-rest
also supports randomized tests for paginated resources assuming you follow
the standard pagination scheme. All you need supply it
with is a block it can use to generate unique parameters for populating the resources prior
to pagination tests. You can specify :count
to control how many records are created and
paginated through (defaults to 512) and :length
to specify the maximum number of resources
that a single index operation may return (defaults to 100).
def test_gauge_pagination
@db.run("DELETE FROM gauges")
paginate_resource(){ |id| {:name => "foo_#{id}", :description => "gauge #{id}"} }
end
Contributions
- Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet
- Check out the issue tracker to make sure someone already hasn't requested it and/or contributed it
- Fork the project
- Start a feature/bugfix branch
- Commit and push until you are happy with your contribution
- Please try not to mess with the Rakefile, version, or history. If you want to have your own version, or is otherwise necessary, that is fine, but please isolate to its own commit so I can cherry-pick around it.
- Submit a pull request!
Copyright
Copyright (c) 2011 Joseph Ruscio. See LICENSE.txt for further details.