I am trying to build a unit test for a REST API I built using Sinatra. For right now I just want to test that my echo function works right. Echo uses POST and will return the exact same payload from the post. I am still new with ruby, so forgive me if I don't use the proper lingo.
Here is the code I want to test:
post '/echo' do
request.body.read
end
This is the unit test I am trying to make:
ENV['RACK_ENV'] = 'test'
require './rest_server'
require 'test/unit'
require 'rack/test'
require 'json'
class RestServer < Test::Unit::TestCase
def app
Sinatra::Application
end
def test_check_methods
data = '{"dataIn": "hello"}'
response = post '/echo', JSON.parse(data)
assert.last_response.ok?
assert(response.body == data)
end
end
With the above code, here is the error:
NoMethodError: undefined method `dataIn' for Sinatra::Application:Class
/Users/barrywilliams/.rvm/gems/ruby-1.9.3-p448/gems/sinatra-1.3.4/lib/sinatra/base.rb:1285:in `block in compile!'
/Users/barrywilliams/.rvm/gems/ruby-1.9.3-p448/gems/sinatra-1.3.4/lib/sinatra/base.rb:1285:in `each_pair'
/Users/barrywilliams/.rvm/gems/ruby-1.9.3-p448/gems/sinatra-1.3.4/lib/sinatra/base.rb:1285:in `compile!'
/Users/barrywilliams/.rvm/gems/ruby-1.9.3-p448/gems/sinatra-1.3.4/lib/sinatra/base.rb:1267:in `route'
/Users/barrywilliams/.rvm/gems/ruby-1.9.3-p448/gems/sinatra-1.3.4/lib/sinatra/base.rb:1256:in `post'
/Users/barrywilliams/.rvm/gems/ruby-1.9.3-p448/gems/sinatra-1.3.4/lib/sinatra/base.rb:1688:in `block (2 levels) in delegate'
/Users/barrywilliams/RubymineProjects/project/rest_server_test.rb:20:in `test_check_methods'
If I try doing it without the JSON.parse
, I get
NoMethodError: undefined method `key?' for "{\"dataIn\": \"hello\"}":String
/Users/barrywilliams/.rvm/gems/ruby-1.9.3-p448/gems/sinatra-1.3.4/lib/sinatra/base.rb:1265:in `route'
/Users/barrywilliams/.rvm/gems/ruby-1.9.3-p448/gems/sinatra-1.3.4/lib/sinatra/base.rb:1256:in `post'
/Users/barrywilliams/.rvm/gems/ruby-1.9.3-p448/gems/sinatra-1.3.4/lib/sinatra/base.rb:1688:in `block (2 levels) in delegate'
/Users/barrywilliams/RubymineProjects/project/rest_server_test.rb:20:in `test_check_methods'
If I try doing it where data = 'hello'
, then I get the same undefined method 'key?'
error
I've tried this suggestion, with no success:
http://softwareblog.morlok.net/2010/12/18/testing-post-with-racktest/
I get an error saying that post
only takes 2 arguments, not 3.
So, in summary, I need to be able to make a call, have the code I'm testing receive the call and return a response, then I need to be able to read that response and verify it was the original data. Right now it looks like it's getting stuck at just making the call.
I did a thing a little similar, it might help you :
The application post definition :
post '/' do
data = JSON.parse request.body.read.to_s
"Hello !\n#{data.to_s}"
end
The .to_s is necessary, else the conversions will not be exactly the same :-/
Then on the test file :
class RootPostTest < Test::Unit::TestCase
include Rack::Test::Methods
def app
Sinatra::Application
end
def test_return_the_parameters
data = {
'reqID' => 1,
'signedReqID' => "plop",
'cert' => "mycert"
}
post '/', data.to_json, "CONTENT_TYPE" => "application/json"
assert last_response.ok?
body_espected = "Hello !\n#{JSON.parse(data.to_json).to_s}"
assert_equal last_response.body, body_espected
end
end
Hope it helped you.
Rack Test will give you back the response body in last_response.body
, no need to save it to a variable. You're also not echoing back what you've sent - data
in the code you've given is JSON, but you converted it to a hash and posted that, so it's not going to match what comes back. Either send JSON, or convert it to JSON in the Sinatra route if you want to do that (see https://stackoverflow.com/a/12138793/335847 for more).
In the Sinatra app:
require 'json'
post '/echo' do
# Don't use request.body.read as you're not posting JSON
params.to_json
end
and in the test file:
def test_check_methods
data = '{"dataIn": "hello"}'
post '/echo', JSON.parse(data)
assert.last_response.ok?
assert(last_response.body == data)
end
If you do end up wanting to post JSON (which I think is usually not a good idea if it's easy to convert or already have the data as a hash) then use :provides => "json"
as a condition to the route, and consider using Rack::Test::Accepts to make life easier writing the test for that (note: that's a shameless plug for a gem I wrote;)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With