31

我在控制器的代码中使用HTTP 状态代码符号,例如:

render json: {
    auth_token: user.authentication_token, 
    user: user
  }, 
  status: :created

或者

render json: {
    errors: ["Missing parameter."]
  }, 
  success: false, 
  status: :unprocessable_entity

在我的请求规范的代码中,我还想使用这些符号:

post user_session_path, email: @user.email, password: @user.password
expect(last_response.status).to eq(201)

...

expect(last_response.status).to eq(422)

但是,我使用符号而不是整数的每个测试都失败了:

Failure/Error: expect(last_response.status).to eq(:created)

  expected: :created
       got: 201

  (compared using ==)

这是Rack 中最新的 HTTP 状态代码符号列表。

4

4 回答 4

27

response对象以消息的形式响应几种符号类型。所以你可以简单地做:

expect(response).to be_success
expect(response).to be_error
expect(response).to be_missing
expect(response).to be_redirect

对于其他类型,例如:created,您可以为此创建一个简单的自定义匹配器,其中包含assert_response

RSpec::Matchers.define :have_status do |type, message = nil|
  match do |_response|
    assert_response type, message
  end
end

expect(response).to have_status(:created)
expect(response).to have_status(404)

对于具有正确状态设置的控制器规格,这应该可以正常工作。它不适用于功能规格。我没有尝试过请求规格,所以你的里程可能会有所不同。

这样做的原因是它利用了 RSpec 控制器规范在幕后具有类似状态设置的事实。所以当assert_response访问@response它是可用的。

只需将使用的代码复制到匹配器中即可改进此匹配assert_response器:

RSpec::Matchers.define :have_status do |type, message = nil|
  match do |response|
    if Symbol === type
      if [:success, :missing, :redirect, :error].include?(type)
        response.send("#{type}?")
      else
        code = Rack::Utils::SYMBOL_TO_STATUS_CODE[type]
        response.response_code == code
      end
    else
      response.response_code == type
    end
  end

  failure_message do |response|
    message or
      "Expected response to be a <#{type}>, but was <#{response.response_code}>"
  end
end

更新:2014-07-02

现在可以使用 RSpec Rails 3 开箱即用:https ://www.relishapp.com/rspec/rspec-rails/v/3-0/docs/matchers/have-http-status-matcher

于 2014-04-07T15:43:23.680 回答
21

这对我有用:

expect(response.response_code).to eq(Rack::Utils::SYMBOL_TO_STATUS_CODE[:not_found])
于 2014-01-08T17:14:20.233 回答
12

一方面,响应是使用以下方法构建的:

  • 成功?

  • 重定向?

  • 无法处理?

  • 完整清单:response.methods.grep(/\?/)

另一方面,Rspec 谓词将每个foo?方法转换为be_foo匹配器。

不幸的是,不确定您是否可以通过这种方式拥有 201,但是创建自定义匹配器非常容易。

注意 Rails 测试只依赖于几个状态

于 2013-08-16T13:55:15.730 回答
12

使用rspec-rails(从rspec 3 开始)可以使用

expect(response).to have_http_status(:created)

2018-06-11 更新

从 Rails 6 开始,一些匹配器将被替换(例如successsuccessful)。

于 2015-01-16T11:27:37.970 回答