3

我正在尝试为以 Backbone 作为前端的 Rails 3.2 编写的 JSON API 编写一组 rspec 测试。我正在编写的测试专门针对 Rails 控制器。

现在,应用程序本身运行良好。当客户端发出带有正文的 PUT 请求时:

{
  "id":1,
  "name":"updated product set",
  ...
}

一切都很好。在后台,Rails 将采用该主体,然后将其转换为:

{
  "id":1,
  "name":"updated product set",
  ...
  "model_name" => { ... }
}

哈希“model_name”指向的位置包含它可以从输入中自动计算出的属性值。一切都很好。

当我从测试环境尝试相同的确切请求时,一切都不好。如果我创建的哈希与上面的 PUT 正文哈希完全相同,但在 rspec 中:

@update_json = {
  "id":1,
  "name":"updated product set",
  ...
}
header "Accept","application/json"
header "Content-type","application/json"
put :update, @update_json

事情根本不解决。在控制器中,如果我检查 params 变量,我会得到:

{ "model_name" => {} }

如果我省略了“Content-type”标题行,我会得到@update_json,但没有Rails 操作来创建我在控制器中需要的“model_name”映射。

我成功运行测试的唯一方法是:

@update_json = {
  :format => "json",
  "id":1,
  "model_name" => {
      "id":1,
      "name":"updated product set",
      ...
  }
}
header "Accept","application/json"
put :update, @update_json

但是,这不是真实世界的测试,因为它没有测试我的骨干前端发送的确切 PUT 主体。

有任何想法吗?

更新:环顾四周,您实际上无法从 rspec 发出真正的 HTTP 请求它只是模拟出来的。例如,您无法让系统以 404 响应,因为 Rails 抛出了一个异常,该异常通常会被 Rails 网络堆栈捕获并变成 404,但在 Rspec 中没有。所以问题看起来比上面的更深......

4

3 回答 3

1

你能试试这个吗?

@update_json = {
  "id":1,
  "model_name" => {
      "id":1,
      "name":"updated product set",
      ...
  }
}
put :update, @update_json, :format => :json

编辑(12 年 11 月 11 日):

您是否尝试过手动实例化请求并查看会发生什么?

诡异的。您是否尝试过“普通的 Ruby 方式”?

env = Rack::MockRequest.env_for('/posts/1', :method => 'PUT', <some other params>)
status, headers, body = PostsController.action(:update).call(env)
...
于 2012-11-03T07:02:12.590 回答
1

我遇到了同样的问题。无论我做了什么,或者我以何种方式将内容类型指定为“应用程序/json”,它都不起作用。如果网上有关于将内容类型设置为 json 的建议,我试了一下。我什至同时尝试了它们。

最终,我追踪到了 ActionController::ParamsWrapper,_wrapper_enabled 在哪里?总是返回 false(由于 request.content_mime_type 为 nil)。这个解决方案对我有用。我也在寻找要添加的“神奇”参数键,并且这样做了。

mime_type = mock
mime_type.stub :ref => :json
request.stub :content_mime_type => mime_type
request.accept = 'application/json'
post :create, widget.as_json

这些值为:

widget.as_json #=> {
  "created_at"=>nil,
  "description"=>"Description 1 - Quidem nihil quae aliquid sed qui.",
  "id"=>nil,
  "order"=>1,
  "title"=>"Title 1 - ut",
  "updated_at"=>nil
}

# params hash in the controller.
params #=> {
  "created_at"=>nil,
  "description"=>"Description 1 - Quidem nihil quae aliquid sed qui.",
  "id"=>nil,
  "order"=>"1",
  "title"=>"Title 1 - ut",
  "updated_at"=>nil,
  "controller"=>"api/widgets",
  "action"=>"create",
  "widget"=>{
    "title"=>"Title 1 - ut",
    "order"=>"1",
    "description"=>"Description 1 - Quidem nihil quae aliquid sed qui."
  }
}

这正是我想要的。只有标题、顺序和描述被设置为 attr_accessible,因此只有出现在神奇创建的 :widget 哈希中的属性。

我也在使用 active_model_serializers,所以 as_json 正在运行,以防有人认为这很重要。

这是我正在构建的公共示例应用程序的一部分,因此如果有人认为它可能有用,则可以在使用中看到此代码。

于 2013-01-25T06:13:17.300 回答
1

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

因此,其他选项可能是升级到 Rails 4 并且事情会按预期工作,或者集成上述提交。

于 2014-02-13T16:36:05.127 回答