使用RSpec测试URL(正则表达式)验证

时间:2017-06-27 21:02:14

标签: ruby-on-rails ruby validation testing rspec

Rails 4.2应用程序有几个模型,其中包含包含URL的属性。网址验证在模型中使用validates :website_url, format: { with: /\A(https?|ftp):\/\/(-\.)?([^\s\/?\.#-]+\.?)+(\/[^\s]*)?\z/i }完成。

我需要使用RSpec 3.5测试URL验证。确保一些众所周知的XSS模式不通过验证并且最常用的URL模式通过验证非常重要。

理想情况下,我想避免为我正在测试的每个有效和无效的网址添加一个测试,以便rspec -fd输出不会受到污染。但是,这可能需要创建两个测试(一个用于有效URL,另一个用于无效URL),并为每个测试添加多个期望(每个URL一个期望),这似乎不太好。

到目前为止,我提出的最佳解决方案是以下共享示例。 你能想到一个更彻底的测试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

修改:为有效和无效的网址添加了context,以便rspec -fd输出更有条理,即使以随机顺序执行了大量的网址验证测试。

1 个答案:

答案 0 :(得分:1)

你的解决方案并不糟糕。我继续使用更多shared_examples

来分解它是有道理的
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

重复的let(:object)让我感到困惑,但我没有立即解决这个问题。