重构rspec测试

时间:2014-11-12 14:00:09

标签: ruby rspec

我写了一个单元测试如下。

describe Youtube::Metadata do
  let(:subject) { SampleMetadata.from_text(open(url)) }
  context "when url is passed" do
    let(:url) { "http://www.sample.com" }

    describe "It should return all values from the site" do
      its(:id) { should eql "234" }
      its(:url) { should eql "www.sample.com" }
    end

    context "Given a html file with id property" do
      let(:html) { File.join(PAGES, 'youtube', 'sample1.html') }
      let(:subject) { Youtube::Metadata.from_text(File.read(html)) }

      it "should return unique value from id property" do
        subject.unique_id.should eql "65155c6e-ba11-42fc-bb91-53520176d2a8"
      end
    end

    context "Given a html file with rel:canonical property" do
      let(:html) { File.join(PAGES, 'youtube', 'sample2.html') }
      let(:subject) { Youtube::Metadata.from_text(File.read(html)) }

      it "should return unique value from rel=canonical content property" do
        subject.unique_id.should eql "65155c6e-ba11-42fc-bb91-53520176d2a8"
      end
    end
  end
end

我需要重构它,以便我不必在每个测试用例中重复以下语句。

let(:subject)   { Youtube::Metadata.from_text(File.read(html))

我在阻止之前尝试了它,但它没有工作。

  

实际上我们传递url的第一个上下文和第二组上下文   我们传递文件名。此外,我不确定是否需要将其作为一个   单个上下文(传递文件名上下文,即最后两个)并描述它。

这样做的正确方法是什么?

4 个答案:

答案 0 :(得分:2)

我认为你提出了很好的问题,但让我们退一步考虑一般的测试。您正在寻找干扰您的测试,因为您认识到重复的代码 - 很棒。测试意味着易于阅读和易于理解。

谢天谢地rspec可让您访问contextdescribe等内容,以便将测试分成几部分。您的测试是分开的,并且您正在使用let变量(这反过来创建实例变量范围),用于您在一次测试中仅使用的内容。

对我来说,这似乎有些过分,而且你会增加一个测试的复杂性,否则这个测试会自动包含在普通it块中。

例如,这似乎是一组更有条理的测试:

describe Youtube::Metadata do
  include Helpers
    # ... omitted ... 

    context "Given a html file with id property" do
      it "should return unique value from id property" do
        subject = file_loader('youtube','sample1.html')
        subject.unique_id.should eql "65155c6e-ba11-42fc-bb91-53520176d2a8"
      end
    end

    context "Given a html file with rel:canonical property" do
      it "should return unique value from rel=canonical content property" do
        subject = file_loader('youtube','sample2.html')
        subject.unique_id.should eql "65155c6e-ba11-42fc-bb91-53520176d2a8"
      end
    end
  end
end

然后只需创建一个帮助器:

module Helpers
  def file_loader(dir, filename)
    file = File.join(PAGES, dir, filename)
    Youtube::Metadata.from_test(file)
  end
end

答案 1 :(得分:1)

您可以使用shared_examples

shared_examples_for "unique id parser" do |sample_file, expected_id|
  let(:html) { File.join(PAGES, 'youtube', sample_file) }
  subject { Youtube::Metadata.from_text(File.read(html)) }

  it "parses unique id property" do
    expect(subject.unique_id).to eql expected_id
  end
end

context "Given a html file with id property" do
  it_behaves_like "unique id parser", 'sample1.html', "65155c6e-ba11-42fc-bb91-53520176d2a8"
end

context "Given a html file with rel:canonical property" do
  it_behaves_like "unique id parser", 'sample2.html', "65155c6e-ba11-42fc-bb91-53520176d2a8"
end

答案 2 :(得分:0)

首先,为第二个和第三个使用另一个名称":subject"因为你已经有一个在outter区。

其次,你真的需要' sample1.html'和' sample2.html'?如果没有,请更改为' sample.html'并且让他们两个都开始。

第三,检查你是否有一些lazzy load的问题(改变让我们!)

答案 3 :(得分:0)

将其与另一个背景分组:

describe Youtube::Metadata do
  # ...
  context "given a html file" do
    subject { Youtube::Metadata.from_text(File.read(file)) }

    context "with id property" do
      let(:file) { File.join(PAGES, 'youtube', 'sample1.html') }

      it "should return unique value from id property" do
        # ...
      end
    end

    context "with rel:canonical property" do
      let(:file) { File.join(PAGES, 'youtube', 'sample2.html') }

      it "should return unique value from rel=canonical content property" do
        # ...
      end
    end
  end
end