重构Rspec规范

时间:2010-04-29 14:43:33

标签: ruby-on-rails ruby rspec bdd

我正在尝试清理我的规格,因为它们变得非常重复。

我有以下规格

  describe "Countries API" do 
    it "should render a country list" do
      co1 = Factory(:country)
      co2 = Factory(:country)
      result = invoke :GetCountryList, "empty_auth"

      result.should be_an_instance_of(Api::GetCountryListReply)
      result.status.should be_an_instance_of(Api::SoapStatus)
      result.status.code.should eql 0
      result.status.errors.should be_an_instance_of Array
      result.status.errors.length.should eql 0
      result.country_list.should be_an_instance_of Array
      result.country_list.first.should be_an_instance_of(Api::Country)
      result.country_list.should have(2).items
    end
    it_should_behave_like "All Web Services"
    it "should render a non-zero status for an invalid request"
  end

检查状态的代码块将出现在50-60个API的所有规范中。我的第一个想法是将其转移到一个方法,并且重构肯定会使事情变得更加干燥如下: -

def status_should_be_valid(status)
    status.should be_an_instance_of(Api::SoapStatus)
    status.code.should eql 0
    status.errors.should be_an_instance_of Array
    status.errors.length.should eql 0
end

describe "Countries API" do 
    it "should render a country list" do
      co1 = Factory(:country)
      co2 = Factory(:country)
      result = invoke :GetCountryList, "empty_auth"

      result.should be_an_instance_of(Api::GetCountryListReply)
      status_should_be_valid(result.status)
      result.country_list.should be_an_instance_of Array
      result.country_list.first.should be_an_instance_of(Api::Country)
      result.country_list.should have(2).items
    end
  end

这有效但我不禁觉得这不是“正确”的方式,我应该使用共享规范,但是看看定义共享规范的方法我不能轻易看出我将如何重构这个示例使用共享规范。

我如何使用共享规范执行此操作,而无需在开始时重新运行相对昂贵的块,即

  co1 = Factory(:country)
  co2 = Factory(:country)
  result = invoke :GetCountryList, "empty_auth"

1 个答案:

答案 0 :(得分:3)

这是一个选项,使用RSpec的新主题“主题”功能。请注意,这将运行before :all块两次,每个嵌套的“describe”块一次。如果这最终太慢,你可以以不能使用状态共享示例的“主题”语法为代价来解决问题(因为主题适用于它所使用的整个描述块)。

shared_examples_for "valid status" do
  it { should be_an_instance_of(Api::SoapStatus) }
  its(:code) { should eql(0) }
  its(:errors) { should be_an_instance_of(Array) }
  its(:errors) { should be_empty }
end

describe "Countries API" do
  before :all do
    co1 = Factory(:country)
    co2 = Factory(:country)
    @result = invoke :GetCountryList, "empty_auth"
  end

  subject { @result }
  it { should be_an_instance_of(Api::GetCountryListReply) }
  its(:country_list) { should be_an_instance_of (Array) }
  it "should have countries in the country list" do
    @result.country_list.each {|c| c.should be_an_instance_of(Api::Country)}
  end
  its(:country_list) { should have(2).items }

  describe "result status" do
    subject { @result.status }
    it_should_behave_like "valid status"
  end
end