如何干掉在多个上下文中重复的测试用例?

时间:2015-09-01 12:14:49

标签: ruby unit-testing rspec

我monkeypatched URI并为它编写测试:

describe URI do
  describe '.sanitize_domain' do
    let(:expectation) { 'toolbar.google.com' }
    subject { described_class.sanitize_domain(url) }

    context 'when url is correct' do
      context 'when url misses both http and www prefixes' do
        let(:url) { 'toolbar.google.com/public' }
        it { is_expected.to eq(expectation) }
      end

      context 'when url contains www' do
        let(:url) { 'www.toolbar.google.com/public' }
        it { is_expected.to eq(expectation) }
      end

      context 'when url contains https' do
        let(:url) { 'https://toolbar.google.com/public' }
        it { is_expected.to eq(expectation) }
      end

      context 'when url contains both http and www' do
        let(:url) { 'http://www.toolbar.google.com/public' }
        it { is_expected.to eq(expectation) }
      end

      context 'when multiple urls are given' do
        let(:url) { 'http://www.toolbar.google.com/Default.asp, http://www.toolbar.google.com/' }
        it { is_expected.to eq(expectation) }
      end
    end
  end
end

如您所见,it { is_expected.to eq(expectation) }在每个上下文中重复出现。

我认为有一种解决办法让它干涸一点。 我可以在这里使用shared_examples,但恕我直言,对单个it执行此操作会有些过分,可读性会降低。

我尝试将expectation提取到before(:context) { it { is_expected } },但it块中没有before关键字。以下是该尝试的错误消息:

  

it在示例(例如it块)中或在示例范围内运行的构造(例如beforelet中不可用,等等)。它仅适用于示例组(例如describecontext块)。

2 个答案:

答案 0 :(得分:1)

inner_contextes_urls = [
  ['when url misses both http and www prefixes', 'toolbar.google.com/public'],
  ['when url contains www', 'www.toolbar.google.com/public']
  # ...
]
inner_contextes_urls.each do |(title, url)|
  context "#{title}" do
    let(:url) { "#{url}" }
    it { is_expected.to eq(expectation) }
  end
end

答案 1 :(得分:1)

对于最小和可读的测试,只需提取一个方法:

describe URI do
  describe '.sanitize_domain' do
    context 'when url is correct' do
      it 'sanitizes a URL without http and www prefixes' do
        expect_sanitized_domain_to_handle 'toolbar.google.com/public'
      end

      it 'sanitizes a URL which contains www' do
        expect_sanitized_domain_to_handle 'www.toolbar.google.com/public'
      end

      it 'sanitizes a URL which contains https' do
        expect_sanitized_domain_to_handle 'https://toolbar.google.com/public'
      end

      it 'sanitizes a URL which contains both http and www' do
        expect_sanitized_domain_to_handle 'https://www.toolbar.google.com/public'
      end

      it 'sanitizes a string containing multiple URLs' do
        expect_sanitized_domain_to_handle 'http://www.toolbar.google.com/Default.asp, http://www.toolbar.google.com/'
      end

      def expect_sanitized_domain_to_handle(url)
        expect(URL.sanitize_domain(url)).to eq('toolbar.google.com')
      end

    end
  end
end

或者,要将预期的返回值放入您可以看到它的测试中,并在需要具有不同返回值的测试时更改它:

it 'sanitizes a URL from a different site' do
  expect_sanitized_domain given: 'http://stackoverflow.com/questions/32331374/the-same-test-case-for-few-contexts-in-rspec-how-to-dry-it',
    to_return: 'stackoverflow.com'
end

def expect_sanitized_domain(given:, to_return:)
  expect(URL.sanitize_domain(given)).to eq(to_return)
end