在RSpec测试中,“放任”实际上可以节省多少时间?

时间:2018-12-28 18:20:03

标签: rspec performance-testing rspec-rails let

我发现仅在代码中设置变量比使用let容易得多。 let挑剔,总是告诉我错误使用它的方式。

当我在规范中使用简单的变量声明时,例如

tx_good = makeTransaction1(),一切正常。

但是当我像这样使用let

let(:tx_good) { makeTransaction1() }我总是会得到一些错误,就像这样告诉我它不能在这里或那里去...

  `let` and `subject` declarations are not intended to be called
   in a `before(:context)` hook, as they exist to define state that
   is reset between each example, while `before(:context)` exists to
   define state that is shared across examples in an example group.

考虑到使用let有多挑剔,我不得不怀疑这样做是否值得我付出更多的努力和谨慎。有谁知道使用let或仅仅预先分配一个变量实际上节省了多少处理时间?

我想遵循良好的测试协议,所以我希望有人可以说服我为什么我应该像其他人一样使用let

1 个答案:

答案 0 :(得分:1)

您用错了这些东西,我理解您的无奈。因此,让我给您一个简化的手册,以供您在RSpec中使用let

使用let时的主要价值并非来自节省的处理能力。它是更广泛的RSpec哲学不可或缺的一部分。我会尽力解释,希望对您来说会更容易...

let很懒

只要且仅在规范中实际使用了块,您在块内定义的任何内容都会被调用:

context do
  let(:foo) { sleep(10000) } # will not happen
  specify { expect(1).to eq(1) }
end 

context do 
  specify do 
     foo = sleep(10000) # you'll wait
     expect(1).to eq(1)
  end
end

使用let!的急切版本(即不偷懒)

let被记住

该块中定义的任何内容仅会发生一次(在上下文范围内):

let

如果您不需要此功能,请定义一个方法:

context do
  let(:random_number) { rand }
  specify do
    expect(random_number).to eq(random_number) # will always pass
  end
end

context do def random_number rand end specify do expect(random_number).to eq(random_number) # sometimes pass, mostly fail end end 在较低级别的上下文中会覆盖较高级别的let定义:

let

^这允许您以某种方式编写规格,其中在上下文中仅提及设置的相关“部分”,例如:

context do
   let(:x) { 1 }
   specify { expect(x).to eq(1) # pass

   context 'with different x' do 
     let(:x) { 2 }
     specify { expect(x).to eq(2) # pass
   end

   context do
     specify { expect(x).to eq(1) # pass
   end
end

奖金:context do let(:x) { 1 } let(:y) { 1 } let(:z) { 1 } specify { expect(foo(x, y, z)).to eq(3) } context 'when z is nil' let(:z) { nil } specify { expect(foo(x, y, z)).to raise_error) } # foo doesn't work with z = nil end context 'when x is nil' let(:x) { nil } specify { expect(foo(x, y, z)).to eq(15) } end end 是一种魔法subject

let

# writing subject { foo(x) } # is almost the same as writing let(:subject) { foo(x) } 是RSpec中的保留概念,它是“您要测试的东西”,因此您可以使用`foo(x,y,z)编写示例,如下所示:

subject

关于您遇到的错误...

  

context do let(:x) { 1 } let(:y) { 1 } let(:z) { 1 } subject { foo(x, y, z) } specify { expect(subject).to eq(3) } context 'when z is nil' let(:z) { nil } specify { expect(subject).to raise_error) } # foo doesn't work with z = nil end context 'when x is nil' let(:x) { nil } specify { expect(foo(subject)).to eq(15) } end end let声明不用于调用   subject钩子,因为它们的存在是为了定义状态   在每个示例之间重置,而before(:context)存在于
  定义在示例组中的示例之间共享的状态。

您正在做类似

before(:context)

只是不要这样做,您可以在before do let(:x) { ... } end let内定义describe,但是可以在{{1}内使用它们(而不是定义它们,使用定义的内容) }和context

before