Sinatra单元测试 - 使用JSON主体的POST请求

5

我正在尝试为使用Sinatra构建的REST API构建单元测试。目前,我只想测试我的回显功能是否正常工作。Echo使用POST并将从该POST返回完全相同的有效负载。由于我在ruby方面还很新,所以请原谅我如果我没有使用适当的术语。

这是我要测试的代码:

post '/echo' do
  request.body.read
end

这是我正在尝试制作的单元测试:

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

使用上述代码后,这是出现的错误:
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'

如果我不使用JSON.parse尝试执行它,我会得到
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'

如果我尝试使用 data = 'hello',那么我会得到相同的错误信息 undefined method 'key?'
我尝试了这个建议,但没有成功: http://softwareblog.morlok.net/2010/12/18/testing-post-with-racktest/ 我收到一个错误消息,说 post 只接受 2 个参数,而不是 3 个。
因此,总结一下,我需要能够发起调用,让我正在测试的代码接收调用并返回响应,然后我需要能够读取该响应并验证它是否为原始数据。目前看来,它似乎只停留在发起调用阶段。

我认为你应该进行集成测试而不是单元测试。单元测试是用于测试类,而不是用于测试请求。也许这个问题会有帮助?https://dev59.com/YWsz5IYBdhLWcg3wR1kc - jamesc
你尝试过直接发布数据结构吗?post 'echo',{"dataIn" => "hello"} - Lars Haugseth
2个回答

10
我曾经做过类似的事情,可能会对您有所帮助:

应用程序发布定义:

post '/' do
    data = JSON.parse request.body.read.to_s
    "Hello !\n#{data.to_s}"
end

".to_s"是必需的,否则转换结果可能不完全相同 :-/
然后,在测试文件中:
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

希望这有帮助。

3
Rack测试将在last_response.body中返回响应正文,无需将其保存到变量中。您也不需要回显您发送的内容 - 在您给出的代码中,data是JSON,但您将其转换为哈希并发布了该哈希,因此它不会与返回的内容匹配。如果要这样做,请发送JSON或在Sinatra路由中将其转换为JSON(有关更多信息,请参见https://dev59.com/Rmct5IYBdhLWcg3wZMfn#12138793)。

在Sinatra应用程序中:

require 'json'

post '/echo' do
  # Don't use request.body.read as you're not posting JSON
  params.to_json
end

并且在测试文件中:

def test_check_methods
  data = '{"dataIn": "hello"}'
  post '/echo', JSON.parse(data)
  assert.last_response.ok?
  assert(last_response.body == data)
end

如果您最终决定要发布JSON(我认为,如果可以将数据轻松转换或已经将数据作为哈希表存在,则通常不是一个好主意),那么请使用:provides => "json"作为路由的条件,并考虑使用Rack::Test::Accepts来更轻松地编写测试(注意:这是我编写的一个宝石的无耻推广;))

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接