How to use HTTP status code symbols in RSpec?

蹲街弑〆低调 提交于 2019-11-29 06:14:03

问题


I use HTTP status code symbols in code in a controller such as:

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

or

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

In the code of my request spec I also would like to use the symbols:

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

...

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

However each test where I use the symbols instead of integers fails:

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

  expected: :created
       got: 201

  (compared using ==)

Here is the latest list of HTTP status code symbols in Rack.


回答1:


On the one hand, response is built with methods like:

  • success?

  • redirect?

  • unprocessable?

  • full list do: response.methods.grep(/\?/)

On the other hand, Rspec predicates transforms every foo? method to a be_foo matcher.

Not sure you can have the 201 this way unfortunately, but creating a custom matcher is quite easy.

Note Rails test only rely on a few statuses.




回答2:


this works for me:

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



回答3:


The response object responds to several of the symbol types as messages. So you can simply do:

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

For the other types, such as :created, you can create a simple custom matcher for this which wraps 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)

This should work fine for controller specs which have the proper state setup. It will not work for feature specs. I haven't tried with request specs, so your milage may vary there.

The reason this works is it leverages the fact that RSpec controller specs have similar state setup behind the scenes. So when assert_response accesses @response it is available.

This matcher can probably be improved by simply copying the code used by assert_response into the matcher:

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

UPDATE: 2014-07-02

This is now available out of the box with RSpec Rails 3: https://www.relishapp.com/rspec/rspec-rails/v/3-0/docs/matchers/have-http-status-matcher




回答4:


With rspec-rails (as of rspec 3) it's possible to use

expect(response).to have_http_status(:created)

Update 2018-06-11:

As of Rails 6, some of the matchers will be replaced (e. g. success by successful).



来源:https://stackoverflow.com/questions/18274709/how-to-use-http-status-code-symbols-in-rspec

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!