在某些RSpec导轨中测试HTTP状态代码以请求示例,但在其他情况下测试引发的异常 [英] Test for HTTP status code in some RSpec rails request exampes, but for raised exception in others

查看:109
本文介绍了在某些RSpec导轨中测试HTTP状态代码以请求示例,但在其他情况下测试引发的异常的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在使用rspec-rails测试过的Rails 4.2.0应用程序中,我提供了一个JSON Web API,该API具有类似REST的资源,并带有强制属性mand_attr.

In a Rails 4.2.0 application tested with rspec-rails, I provide a JSON web API with a REST-like resource with a mandatory attribute mand_attr.

我想测试POST请求中缺少该属性时,该API是否使用HTTP代码400(BAD REQUEST)答复.(请参见第二个示例打击).我的控制器尝试执行以下操作:如下面的第一个RSpec示例所示,通过引发ActionController::ParameterMissing导致此HTTP代码.

I'd like to test that this API answers with HTTP code 400 (BAD REQUEST) when that attribute is missing from a POST request. (See second example blow.) My controller tries to cause this HTTP code by throwing an ActionController::ParameterMissing, as illustrated by the first RSpec example below.

other RSpec示例中,我希望这些示例可以挽救提出的异常(如果可以预期的话),或者可以击中测试运行程序,因此可以将它们显示给开发人员(如果错误是意外的),因此我不想删除

In other RSpec examples, I want raised exceptions to be rescued by the examples (if they're expected) or to hit the test runner, so they're displayed to the developer (if the error is unexpected), thus I do not want to remove

  # Raise exceptions instead of rendering exception templates.
  config.action_dispatch.show_exceptions = false

来自config/environments/test.rb.

我的计划是在请求规范:

describe 'POST' do
  let(:perform_request) { post '/my/api/my_ressource', request_body, request_header }
  let(:request_header) { { 'CONTENT_TYPE' => 'application/json' } }

  context 'without mandatory attribute' do
    let(:request_body) do
      {}.to_json
    end

    it 'raises a ParameterMissing error' do
      expect { perform_request }.to raise_error ActionController::ParameterMissing,
                                                'param is missing or the value is empty: mand_attr'
    end

    context 'in production' do
      ###############################################################
      # How do I make this work without breaking the example above? #
      ###############################################################
      it 'reports BAD REQUEST (HTTP status 400)' do
        perform_request
        expect(response).to be_a_bad_request
        # Above matcher provided by api-matchers. Expectation equivalent to
        #     expect(response.status).to eq 400
      end
    end
  end

  # Below are the examples for the happy path.
  # They're not relevant to this question, but I thought
  # I'd let you see them for context and illustration.
  context 'with mandatory attribute' do
    let(:request_body) do
      { mand_attr: 'something' }.to_json
    end

    it 'creates a ressource entry' do
      expect { perform_request }.to change(MyRessource, :count).by 1
    end

    it 'reports that a ressource entry was created (HTTP status 201)' do
      perform_request
      expect(response).to create_resource
      # Above matcher provided by api-matchers. Expectation equivalent to
      #     expect(response.status).to eq 201
    end
  end
end

我找到了两个可行的解决方案和一个部分可行的解决方案,我将其作为答案发布.但是我对它们中的任何一个都不特别满意,因此,如果您能提出更好的东西(或只是有所不同),我想看看您的方法!另外,如果请求规范是我想知道的是测试类型错误的规范.

I have found two working and one partially working solutions which I'll post as answers. But I'm not particularly happy with any of them, so if you can come up with something better (or just different), I'd like to see your approach! Also, if a request spec is the wrong type of spec to test this, I'd like to know so.

我预见到了问题

所以让我先发制人地回答:我觉得我不是在这里测试框架本身,而是我是否在正确地使用 框架.我的控制器不是从ActionController::Base继承,而是从ActionController::API继承,我不知道ActionController::API是默认使用ActionDispatch::ExceptionWrapper还是我是否首先必须告诉我的控制器以某种方式这样做.

so let me answer that pre-emptively: I feel I'm not testing the framework itself here, but whether I'm using the framework correctly. My controller doesn't inherit from ActionController::Base but from ActionController::API and I didn't know whether ActionController::API uses ActionDispatch::ExceptionWrapper by default or whether I first would have had to tell my controller to do so somehow.

推荐答案

您要使用

You'd want to use RSpec filters for that. If you do it this way, the modification to Rails.application.config.action_dispatch.show_exceptions will be local to the example and not interfere with your other tests:

# This configure block can be moved into a spec helper
RSpec.configure do |config|
  config.before(:example, exceptions: :catch) do
    allow(Rails.application.config.action_dispatch).to receive(:show_exceptions) { true }
  end
end

RSpec.describe 'POST' do
  let(:perform_request) { post '/my/api/my_ressource', request_body }

  context 'without mandatory attribute' do
    let(:request_body) do
      {}.to_json
    end

    it 'raises a ParameterMissing error' do
      expect { perform_request }.to raise_error ActionController::ParameterMissing
    end

    context 'in production', exceptions: :catch do
      it 'reports BAD REQUEST (HTTP status 400)' do
        perform_request
        expect(response).to be_a_bad_request
      end
    end
  end
end

exceptions: :catch在RSpec中是任意元数据",我在这里选择命名以提高可读性.

The exceptions: :catch is "arbitrary metadata" in RSpec speak, I chose the naming here for readability.

这篇关于在某些RSpec导轨中测试HTTP状态代码以请求示例,但在其他情况下测试引发的异常的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆