【问题标题】:How to use HTTP status code symbols in RSpec?如何在 RSpec 中使用 HTTP 状态码符号?
【发布时间】:2013-08-16 13:39:25
【问题描述】:

我在控制器的代码中使用HTTP status code symbols,例如:

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 ==)

这是HTTP status code symbols in Rack的最新列表。

【问题讨论】:

    标签: ruby-on-rails rspec http-status-codes human-readable


    【解决方案1】:

    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

    【讨论】:

      【解决方案2】:

      这对我有用:

      expect(response.response_code).to eq(Rack::Utils::SYMBOL_TO_STATUS_CODE[:not_found])
      

      【讨论】:

        【解决方案3】:

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

        • 成功了吗?

        • 重定向?

        • 无法处理?

        • 完整列表:response.methods.grep(/\?/)

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

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

        注意 Rails 仅测试 rely on a few statuses

        【讨论】:

        • 我试过 expect(last_response.status).to be_created 失败了 "undefined method `created?'对于 201:Fixnum".
        • expect(last_response).to be_success
        • 相同:expect(last_response.status).to be_success 失败,"未定义方法'成功?'对于 201:Fixnum"。我知道created? 不在列表中,并尝试使用自定义匹配器......不过现在没有成功。
        • 重读我写的:expect(last_response) 不是expect(last_response.status)
        • 请求规格?请求规范应位于spec/features,控制器规范应位于spec/controllers,否则将添加错误的模块(除非您手动包含它们)
        【解决方案4】:

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

        expect(response).to have_http_status(:created)
        

        2018 年 6 月 11 日更新

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

        【讨论】:

        • 仅在 RSpec 版本 3 或更高版本中。 have_http_status 不包含在 RSpec 2 中。
        猜你喜欢
        • 2014-10-13
        • 1970-01-01
        • 2014-08-03
        • 1970-01-01
        • 2012-07-10
        • 2011-02-26
        • 2018-10-12
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多