在 RSpec 测试中“let”真正节省了多少时间?

2024-01-01

我发现在代码中设置变量比使用变量容易得多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就像(看起来)其他人一样。


你用错了这些东西,我理解你的沮丧。所以让我给你一份简明的使用手册letRSpec 中的 s。

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

let is lazy

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

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

Use 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

Bonus: subject是一个魔法let

# writing 
subject { foo(x) }
# is almost the same as writing 
let(:subject) { foo(x) }

subject是 RSpec 中的保留概念,它是“您测试的东西”,因此您可以使用 `foo(x, y, z) 编写示例,如下所示:

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 and subject声明不打算被调用 Abefore(:context)钩子,因为它们的存在是为了定义状态 在每个示例之间重置,同时before(:context)存在于
定义在示例组中的示例之间共享的状态。

你正在做类似的事情

before do
  let(:x) { ... }
end

只是不这样做,你定义let inside describe and context,但您可以在内部使用它们(不是定义它们,而是使用定义的内容)before and specify:

let(:name) { 'Frank' }
before do
  User.create name: name
end

specify do
   expect(User.where(name: name).count).to eq(1)
end
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

在 RSpec 测试中“let”真正节省了多少时间? 的相关文章

随机推荐