避免在RSpec中重新创建主题

时间:2014-10-02 12:55:31

标签: ruby-on-rails ruby testing rspec

说我有以下测试

describe "bob" do
  subject { 
    response = get "/expensive_lookup"
    JSON.parse(response.body) 
  }

  its(["transaction_id"]) { should == 1 }
  its(["order_id"]) { should == 33 }
end

然后对于每个its() {},主题将被重新评估,在我的情况下,这是一个非常慢的查找。

我可以将所有测试捆绑在一起,例如

describe "bob" do
  subject(res) { 
    response = get "/expensive_lookup"
    JSON.parse(response.body) 
  }

  it "returns the right stuff" do
    res["transaction_id"]).should == 1
    res["order_id"].should == 33
  end
end

但是,如果发生故障,这会使测试的哪一行失败变得不那么明显。

有没有办法可以阻止每个it块重新评估主题?

2 个答案:

答案 0 :(得分:3)

您可以将其放入before(:all)块。我不知道新的rspec版本中的语法是否已经改变,但无论如何,你的测试都会变成这样:

before(:all) do
  response = get "/expensive_lookup"
  @res = JSON.parse(response.body)
end

it "returns the right transaction ID" do
  @res["transaction_id"].should == 1
end

# etc

专家认为,前所有块中的代码只为您的规范运行一次。可以看出,正如你所看到的,你无法利用这个主题;你需要更明确地写出每一个。另一个问题是,保存到测试数据库的任何数据都不是事务的一部分,也不会回滚。

答案 1 :(得分:1)

有两个可能的问题来源

网络请求缓慢/容易失败

您应该真正嘲笑所有网络请求,无论是否缓慢。

宝石VCR非常棒。只需运行一次请求并保留结果以进行后续测试,就变得微不足道了。

建立不变的主题很慢

如果您有多个it区块,则主题将每次都重建。有一种避免这种情况的方法:

let(:expensive) { very_long_computation }
subject { @cache ||= expensive.freeze }

it { is_expected.to have_attributes(foo: 42) }

it { is_expected.to # ... }

这样very_long_computation仅运行一次,并且在两个it块中共享。

注意:我在freeze块中调用subject是为了避免错误地对其进行修改,但是当然这并不是很深的冻结,因此您仍然需要注意什么你在做。如果您要更改主题,则测试将不再独立,并且不应共享主题。