2016-05-02 10 views
1

私は、API呼び出しからのHTTPヘッダーがすべて受け入れ可能なヘッダーのリスト(受け入れ可能な値も含む)に含まれていることを主張する仕様を書こうとしています。RSpecでは、ヘッダが許容可能な値のリストに含まれることを期待するには?

私はこのような何か書いてしまった:

RSpec::Matchers.define :be_included_in do |enumerable| 
    match do |element| 
    enumerable.include?(element) 
    end 
end 

これはヘッダが含まれるすべての範囲内にあることを主張するためにうまく機能しませんが:be_included_inは、カスタム照合で

expect(response.headers).to all(be_included_in(acceptable_headers)) 

を受諾のためにその値をテストするという要件を満たしている。

どのようにこれをエレガントに行うためのアイデアですか?

+0

がそれぞれ許容ヘッダが許容値の既知のセットを持っていないか、許容値は、各許容ヘッダーの正規表現のような単純なもので識別することができ、あるいはより複雑な何かが必要とされるであろう。この正規表現はそれを処理します?また、あなたのマッチャーの '!'はタイプミスですか? –

+0

受け入れられた値は、RSpecマッチャーで表現するのに十分シンプルです(ただし、複雑な条件にもrspecマッチャーがあります)。私は実際にフィードバックを受け取る答えとして投稿するソリューションを考え出しました。あなたが正しいです、マッチャーの '!'はタイプミスです! –

+0

受け入れ可能なヘッダーのリスト内のヘッダーが存在しない場合(誤った値を持つのとは対照的に)、テストは合格しますか? –

答えて

0

これは、既存のマッチャー、否定マッチャー、および実在のロジックマジックでは可能です。

否定マッチャ:

RSpec::Matchers.define_negated_matcher :does_not_include, :include 
RSpec::Matchers.alias_matcher :a_hash_not_including, :does_not_include 

受理ヘッダ:

let(:acceptable_headers) do 
    { 
    'Content-Type' => be_a(String) 
    } 
end 

スペック "これはのみ許可ヘッダを返す" ここ

はコンポーネントです。ここのロジック担当者は、これが "許可され​​たヘッダーに含まれていないヘッダーを返さない"と書き直すことができることを今すぐ知っています。だから、それは行く:

it 'includes only allowed headers' do 
    expect(some_result).to match(
     a_hash_not_including(
     headers: a_hash_not_including(acceptable_headers) 
    ) 
    ) 
    end 
2

はここでヘッダー-名=> RSpecのマッチャのハッシュに対して実際のヘッダを吟味するというアイデアであなたの最初の試みのスタイルを組み合わせたソリューションです。

  • expect()コールで応答からヘッダを取得する簡単なマッチャーを保持し、それがすべての誰もがHTTPを知っているので、考えるのは簡単です、ヘッダー、程度とすることができます:それは、以下を実現します。
  • 否定マッチャーを使用しないため、複数の否定がある解決策よりも考えるのが簡単です。
  • これは、あなたのダブルネガティブな解決策ではありませんが、以下で説明します。

    # I changed the first acceptable header and added a second to test that 
    # the matcher handles multiple acceptable headers correctly 
    let(:acceptable_headers) do 
        { 
        'Content-Type' => match(/^[a-z\-_.]+\/[a-z\-_.]+$/), 
        'Content-Length' => match(/^\d+$/) 
        } 
    end 
    
    RSpec::Matchers.define :all_be_acceptable_headers do 
        match do |actual| 
        actual.all? do |actual_key, actual_value| 
         acceptable_headers.any? do |acceptable_key, acceptable_value| 
         actual_key == acceptable_key && acceptable_value.matches?(actual_value) 
         end 
        end 
        end 
    
        # This is better than the default message only in that it lists acceptable headers. 
        # An even better message would identify specific unacceptable headers. 
        failure_message do |actual| 
        "expected that #{actual} would match one of #{acceptable_headers}" 
        end 
    
    end 
    

    は、それはあなたの二重否定ソリューションはまた、ハンドルこれらの例を処理します:ここで

は、正規表現エンジンの

expect({ 'Content-Type' => "application/xml" }).to all_be_acceptable_headers 
expect({ 'Content-Type' => "application/xml", 'Content-Length' => "123" }).to all_be_acceptable_headers 
expect({ 'Content-Tape' => "application/xml" }).not_to all_be_acceptable_headers 
expect({ 'Content-Type' => "not a content type" }).not_to all_be_acceptable_headers 

あなたのダブルネガティブソリューションを通過した場合headers:キーと値のペアそれは決して起こらないかもしれないが、私はそれがすべきではないと思う。可能な限りユーザーフレンドリーではないと思われる場合は、nilで呼び出された場合はNoMethodErrorが発生します。繰り返しますが、主な点は、レスポンスを正規表現の問題にするのはちょうどいいことです。

この正規表現は、2つのケースを扱うあなたの二重否定的解決策がありません:

  • 空のヘッダハッシュが通過する必要があります

    expect({}).to all_be_acceptable_headers 
    
  • をRSpecののincludeは驚くべき行動を持っている(これは私は、あなたの解決策がなぜ正しく見えなかったかを理解しながら発見しました):in

    expect([0]).to include(0, 1) 
    

    includeinclude_all_ofと扱われるため、上記は失敗します。しかし

    expect([0]).not_to include(0, 1) 
    

    includeinclude_any_ofとして扱うので、上記のは、あまりにも失敗しています!

    複数の許容可能なヘッダーがあり、実際のヘッダーハッシュに1つの受け入れ可能なヘッダーと1つの受け入れがたいヘッダーがある場合、2重否定の解決策は成功します。

    expect({ 'Content-Type' => "not a content type", 'Content-Length' => "123" }). 
        not_to all_be_acceptable_headers 
    
関連する問題