【问题标题】:Refactoring Rspec specs重构 Rspec 规范
【发布时间】:2010-04-29 14:43:32
【问题描述】:

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

我有以下规格

  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"

【问题讨论】:

    标签: ruby-on-rails ruby rspec bdd


    【解决方案1】:

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

    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
    

    【讨论】:

    • 这有几个奇怪的问题。之前 :all 抛出以下错误 NoMethodError in 'AdminlwController Countries API before(:all)' undefined method recycle!'对于 nil:NilClass` 更改为 before(:each) 会走得更远,但在 its(:country_list) 上很糟糕,我想我会开始一个新问题。
    • 是的 - 显然,我无权访问您的代码(我针对一些完全模拟出来的对象运行了这个测试,以确保语法正确,但就是这样),所以可能有我不知道的问题。
    • 顺便问一下,您使用的是哪个版本的 RSpec? its() 功能是在 1.2.9 版本中添加的。
    • 我刚开始遇到问题时升级到了最新版本 (1.3.0)。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-10-16
    • 2020-07-22
    • 2013-03-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多