【问题标题】:How do I test my JSON API with Sinatra + rspec如何使用 Sinatra + rspec 测试我的 JSON API
【发布时间】:2013-02-07 06:48:27
【问题描述】:

我有一个接受 JSON 的 post 方法:

post '/channel/create' do
  content_type :json

  @data = JSON.parse(env['rack.input'].gets)

  if @data.nil? or !@data.has_key?('api_key')
    status 400
    body({ :error => "JSON corrupt" }.to_json)
  else
    status 200
    body({ :error => "Channel created" }.to_json)
  end

作为 rspec 的新手,我很困惑试图弄清楚如何使用可接受的 JSON 有效负载针对该 POST 编写测试。我最接近的是这个非常不准确,但我似乎没有向谷歌上帝问正确的问题来帮助我。

  it "accepts create channel" do
    h = {'Content-Type' => 'application/json'}
    body = { :key => "abcdef" }.to_json
    post '/channel/create', body, h
    last_response.should be_ok
  end

任何在 Sinatra 中测试 API 的最佳实践指南也将不胜感激。

【问题讨论】:

标签: api rspec sinatra


【解决方案1】:

您使用的代码很好,虽然我的结构会略有不同,因为我不喜欢像您通常看到的那样使用 it 块,我认为它鼓励测试多个方面一次系统:

let(:body) { { :key => "abcdef" }.to_json }
before do
  post '/channel/create', body, {'CONTENT_TYPE' => 'application/json'}
end
subject { last_response }
it { should be_ok }

我使用了let,因为它比before 块中的实例变量更好(感谢您不这样做)。 post 位于 before 块中,因为它实际上并不是规范的一部分,而是在您指定之前发生的副作用。 subject 是响应,这使得 it 成为一个简单的调用。

因为需要检查响应是否正常,所以我经常将其放在shared example

shared_examples_for "Any route" do
  subject { last_response }
  it { should be_ok }
end

然后这样称呼它:

describe "Creating a new channel" do
  let(:body) { { :key => "abcdef" }.to_json }
  before do
    post '/channel/create', body, {'CONTENT_TYPE' => 'application/json'}
  end
  it_should_behave_like "Any route"
  # now spec some other, more complicated stuff…
  subject { JSON.parse(last_response.body) }
  it { should == "" }

而且因为内容类型经常变化,我把它放在一个助手中:

  module Helpers

    def env( *methods )
      methods.each_with_object({}) do |meth, obj|
        obj.merge! __send__(meth)
      end
    end

    def accepts_html
      {"HTTP_ACCEPT" => "text/html" }
    end

    def accepts_json 
      {"HTTP_ACCEPT" => "application/json" }
    end

    def via_xhr      
      {"HTTP_X_REQUESTED_WITH" => "XMLHttpRequest"}
    end

通过 RSpec 配置将其添加到需要的位置很容易:

RSpec.configure do |config|
  config.include Helpers, :type => :request

然后:

describe "Creating a new channel", :type => :request do
  let(:body) { { :key => "abcdef" }.to_json }
  before do
    post '/channel/create', body, env(:accepts_json)
  end

说了这么多,就我个人而言,我不会使用 JSON 发帖。 HTTP POST 处理起来很简单,每个表单和 javascript 库都可以轻松、很好地完成它。无论如何都用 JSON 响应,但不要发布 JSON,HTTP 更容易。


编辑:写出上面的Helpers 位后,我意识到it would be more helpful as a gem

【讨论】:

    【解决方案2】:

    看起来post :update, '{"some": "json"}' 的功能已添加到此提交中 rspec 使用的内部 ActionPack test_case.rb 中: https://github.com/rails/rails/commit/5b9708840f4cc1d5414c64be43c5fc6b51d4ecbf

    由于您使用的是 Sinatra,因此我不确定获得这些更改的最佳方法 - 您可能可以直接升级 ActionPack,或从上述提交中修补。

    【讨论】:

      【解决方案3】:

      如果你想把 last_response 看成 JSON,你可以试试rack-test-json which makes this trivial:

      expect(last_response).to be_json
      expect(last_response.as_json['key']).to be == 'value'
      

      【讨论】:

        猜你喜欢
        • 2017-06-19
        • 1970-01-01
        • 2011-11-17
        • 1970-01-01
        • 2018-01-02
        • 1970-01-01
        • 2013-10-30
        • 2012-06-28
        • 2011-01-26
        相关资源
        最近更新 更多