2016-05-02 34 views
1

我想寫一個規範,聲明來自API調用的HTTP頭都包含在可接受的頭文件列表中(也有可接受的值)。在RSpec中,如何期望標題包含在可接受值列表中?

我最後寫是這樣的:

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

其中be_included_in是一個自定義匹配:

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

這非常適用於斷言頭都在包含的範圍內,但不滿足測試其驗收值的要求。

任何想法如何優雅地做到這一點?

+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,如果這種匹配不盡可能方便用戶,則可能是正確的。同樣,主要的一點是,讓答案不是匹配者的問題更好。

這個匹配也處理兩個案件的雙負解不:

  • 一個空的頭哈希應該通過:

    expect({}).to all_be_acceptable_headers 
    
  • 的RSpec的include有一個令人驚訝的行爲(其中我發現雖然弄清楚爲什麼你的解決方案似乎並不完全正確):在

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

    include被視爲include_all_of,因此上述失敗。但在

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

    include被視爲include_any_of,所以上面的失敗呢!

    正因爲如此,如果有多個可以接受的頭和實際標題的哈希具有一個可接受的報頭和一個報頭不可接受的雙負溶液流。這種匹配處理是:

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