2017-06-27 8 views
0

Rails 4.2アプリケーションには、URLを含む属性を持つモデルがいくつかあります。 URL検証はvalidates :website_url, format: { with: /\A(https?|ftp):\/\/(-\.)?([^\s\/?\.#-]+\.?)+(\/[^\s]*)?\z/i }のモデルで実行されます。RSpecによるURL(正規表現)検証のテスト

RSpec 3.5でURL検証をテストする必要があります。いくつかのよく知られているXSSパターンが検証に合格しないこと、そして最も一般的に使用されるURLパターンが検証に合格することを確認することが重要です。

rspec -fdの出力が汚染されないように、理想的には、私がテストしている有効で無効なURLごとに1つのテストを追加することを避けたいと思います。しかし、おそらく2つのテスト(有効なURL用と無効なURL用)を作成し、各テストに複数の期待を追加する必要があります(URLあたり1つの期待)。

私が今までに思いついた最善の解決策は、次の共有例です。 URL検証を徹底的にテストするためのより良い方法はありますか?モデルの仕様の中で

RSpec.shared_examples "url validation" do |attribute| 
    INVALID_URLS = [ 
     "invalidurl", 
     "inval.lid/urlexample", 
     "javascript:dangerousJs()//http://www.validurl.com", 
     # Literal array is required for \n to be parsed 
     "http://www.validurl.com\n<script>dangerousJs();</script>" 
    ] 

    VALID_URLS = [ 
     "http://validurl.com", 
     "https://validurl.com/blah_blah" 
    ] 

    context "with invalid URLs in #{attribute}" do 
    INVALID_URLS.each do |url| 
     it "is invalid with #{url}" do 
     object = FactoryGirl.build(factory_name(subject), attribute => url) 
     object.valid? 
     expect(object.errors[attribute]).to include("is invalid") 
     end 
    end 
    end 

    context "with valid URLs in #{attribute}" do 
    VALID_URLS.each do |url| 
     it "is valid with #{url}" do 
     object = FactoryGirl.build(factory_name(subject), attribute => url) 
     expect(object).to be_valid 
     end 
    end 
    end 

include_examples "url validation", :website_url 

編集:でもランダムに実行URLの検証テストの数が多いので、rspec -fd出力をよりよく組織化され、有効と無効なURLのcontextを追加しました注文。

答えて

1

あなたの解決策は悪くありません。繰り返しlet(:object)バグ私

RSpec.shared_examples "an invalid URL for attribute" do |url, attribute| 
    let(:object) { FactoryGirl.build(factory_name(subject), attribute => url) } 
    before(:each) { object.valid? } 
    specify { expect(object.errors[attribute]).to include("is invalid") } 
end 

RSpec.shared_examples "a valid URL for attribute" do |url, attribute| 
    let(:object) { FactoryGirl.build(factory_name(subject), attribute => url) } 
    specify { expect(object).to be_valid } 
end 

RSpec.shared_examples "URL validation" do |attribute| 
    [ "invalidurl", 
    "inval.lid/urlexample", 
    # ... 
    ].each do |url| 
    it_behaves_like "a valid URL for attribute", url, attribute 
    end 

    [ "http://validurl.com", 
    "https://validurl.com/blah_blah" 
    ].each do |url| 
    it_behaves_like "an invalid URL for attribute", url, attribute 
    end 
end 

、私はそれのための即時のソリューションを持っていない:それはshared_examples以上でそれを打破し続けることが私には意味があります。

+0

ご回答ありがとうございます。私も試したが、オブジェクトの作成を繰り返すことを避けることができませんでした。同じshared_examplesブロック内であっても、ループ内のURLを 'let'ブロックに渡すのは面倒でした。 – BrunoFacca

+0

@BrunoFacca明確にするために、あなたのユースケースでは上記の解決策が使えますか?問題がある場合は教えてください。 –

+0

それは動作します。しかし、このように分割するメリット(3つの共有例を作成する)を説明してください。このアプローチは賢明で洗練されていますが、反復やLOCを減らすことなく複雑さを増やしてくれます。あなたの経験からすれば、私はおそらく何かを欠いているでしょう。 – BrunoFacca