重构 Rspec 规范

发布于 2024-08-30 09:10:22 字数 1868 浏览 1 评论 0原文

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

我有以下规范

  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"

I am trying to cleanup my specs as they are becoming extremely repetitive.

I have the following spec

  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

The block of code that checks the status will appear in all of my specs for 50-60 APIs. My first thought was to move that to a method and that refactoring certainly makes things much drier as follows :-

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

This works however I can not help feeling that this is not the "right" way to do it and I should be using shared specs, however looking at the method for defining shared specs I can not easily see how I would refactor this example to use a shared spec.

How would I do this with shared specs and without having to re-run the relatively costly block at the beginning namely

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

陌若浮生 2024-09-06 09:10:22

这是一种选择,使用 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

Here's one option, using the new-ish "subject" feature of RSpec. Note that this will run the before :all block twice, once for each nested "describe" block. If this ends up being too slow, you can flatten things out at the cost of not being able to use the "subject" syntax for the status shared examples (since subject applies to the entire describe block it's used in).

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
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文