20

でテストされた Rails 4.2.0 アプリケーションでrspec-railsは、JSON Web API に REST に似たリソースを必須属性で提供しますmand_attr

BAD REQUESTこの属性が POST リクエストにない場合、この API が HTTP コード 400 ( ) で応答することをテストしたいと思います。ActionController::ParameterMissing(以下の 2 番目の例を参照してください。) 私のコントローラーは、以下の最初の RSpec の例に示されているように、 をスローすることによって、この HTTP コードを引き起こそうとします。

RSpec の例では、発生した例外を例によってレスキューする (予想される場合) か、テスト ランナーをヒットして、開発者に表示されるようにする (エラーが予期しない場合) ことを望んでいます。削除する

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

からconfig/environments/test.rb

私の計画は、 request specに次のようなものを含めることでした:

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

回答として投稿する2つの機能するソリューションと1つの部分的に機能するソリューションを見つけました。しかし、私はそれらのどれにも特に満足しているわけではないので、より良い (またはまったく異なる) 何かを思いつくことができれば、あなたのアプローチを見てみたいです! また、リクエスト スペックがこれをテストするのに不適切なタイプのスペックである場合は、そのことを知りたいです。

私はその質問を予見します

Rails アプリケーションだけでなく、Rails フレームワークをテストするのはなぜですか? Rails フレームワークには独自のテストがあります。

ここでフレームワーク自体をテストしているのではなく、フレームワークを正しく使用しているかどうかをテストしていると思います。ActionController::Base私のコントローラーはから継承していませんが、デフォルトで使用するかどうか、または最初にコントローラーに何らかの方法でそうするように指示する必要があるかどうかはActionController::APIわかりませんでした。ActionController::APIActionDispatch::ExceptionWrapper

4

5 に答える 5

6

そのためにRSpecフィルターを使用したいと思うでしょう。このようにすると、 への変更Rails.application.config.action_dispatch.show_exceptionsは例に対してローカルになり、他のテストに干渉しなくなります。

# 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 で言えば「任意のメタデータ」です。ここでは読みやすくするためにこの名前を付けました。

于 2016-02-17T08:04:13.600 に答える
0

nil部分的にモックされたアプリケーション構成から戻る

    context 'in production' do
      before do
        allow(Rails.application.config.action_dispatch).to receive(:show_exceptions)
      end

      it 'reports BAD REQUEST (HTTP status 400)' do
        perform_request
        expect(response).to be_a_bad_request
      end
    end

またはより明示的に

    context 'in production' do
      before do
        allow(Rails.application.config.action_dispatch).to receive(:show_exceptions).and_return nil
      end

      it 'reports BAD REQUEST (HTTP status 400)' do
        perform_request
        expect(response).to be_a_bad_request
      end
    end

それが実行されている唯一の例である場合に機能します。しかし、そうであれば、 から設定を削除することもできるconfig/environments/test.rbので、これは少し議論の余地があります。がこの設定を照会し、その結果をキャッシュするため、いくつかの例がある場合、これは機能しません。Rails.application.env_config()

于 2015-04-04T11:18:03.750 に答える
0

Rails.application.env_config()変更された結果を返すためのモック

    context 'in production' do
      before do
        # We don't really want to test in a production environment,
        # just in a slightly deviating test environment,
        # so use the current test environment as a starting point ...
        pseudo_production_config = Rails.application.env_config.clone

        # ... and just remove the one test-specific setting we don't want here:
        pseudo_production_config.delete 'action_dispatch.show_exceptions'

        # Then let `Rails.application.env_config()` return that modified Hash
        # for subsequent calls within this RSpec context.
        allow(Rails.application).to receive(:env_config).
                                        and_return pseudo_production_config
      end

      it 'reports BAD REQUEST (HTTP status 400)' do
        perform_request
        expect(response).to be_a_bad_request
      end
    end

トリックを行います。すべての例に影響を与える元のハッシュを変更しないように、cloneからの結果であることに注意してください。env_config()

于 2015-04-04T11:33:29.613 に答える
0
    context 'in production' do
      around do |example|
        # Run examples without the setting:
        show_exceptions = Rails.application.env_config.delete 'action_dispatch.show_exceptions'
        example.run

        # Restore the setting:
        Rails.application.env_config['action_dispatch.show_exceptions'] = show_exceptions
      end

      it 'reports BAD REQUEST (HTTP status 400)' do
        perform_request
        expect(response).to be_a_bad_request
      end
    end

トリックを行いますが、ちょっと汚い感じがします。Rails.application.env_config()結果をキャッシュするために使用する基礎となるハッシュへのアクセスを提供するため、機能するため、直接変更できます。

于 2015-04-04T11:24:56.657 に答える