Sinatra unit test - post with JSON body

user2718753 picture user2718753 · Aug 26, 2013 · Viewed 7.6k times · Source

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.

Thanks, Barry

Answer

shamox picture shamox · Apr 18, 2014

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.