小编baw*_*ver的帖子

RSPEC Let vs Instance具有昂贵的对象创建

在RSPEC中,Let的行为是在单个示例中进行记忆(它阻止),但是在某些情况下,就时序而言,这可能会导致一些潜在的讨厌的副作用。

我注意到,如果您设法尝试创建任何被认为昂贵的东西,例如大型模拟,则将在调用它的每个示例中重复整个对象的创建过程。

解决此问题的第一步是将模拟数据缩小到一定大小,这将大部分运行时间从〜30秒减少到〜.08秒。给出的结果是,通过将一个被调用了3次且没有任何形式突变的let变量传递给实例,速度可以提高得更多(在这种情况下,从-0.02到-0.04)。

通常,可以认为延迟评估是可取的,并且在某些情况下,这样做是安全的代价。在大型测试套件(3000多个测试)的情况下,甚至0.01-0.02秒的差异通常足以导致20-30秒的膨胀。当然,在某些情况下,这是任意编号,但是您可以看到为什么这是不希望的,并产生复合问题。

我的问题是:

  • 在什么情况下不再可行?
  • 有什么办法可以在块上下文而不是示例上下文中扩展其记忆吗?...或者这是一个可怕的想法?
  • 是否有有效的方法来生成大量的模拟数据,而这些模拟数据的加载时间可能不会超过7秒?我看到过模糊的提及《工厂女郎》,但在该笔记上有足够的争论,我不知道在当前情况下该怎么想。

感谢您的时间!

ruby rspec mocking let factory-bot

5
推荐指数
1
解决办法
916
查看次数

RSPEC允许替代范围

let的正常行为本质上是绑定到一个示例块(即,它阻塞.)这在大多数情况下都很好,但是如果您碰巧在let中创建大型对象(在多个示例中使用),则会出现严重问题.在这种情况下,实例变量几乎成为测试套件健全性的必要条件.

时间将如此复合:

  • let =#个例子在*对象创建时调用
  • instance =对象创建时间

在调用的示例数超过3的情况下,此时间很快成为问题.

大多数人会说使用实例变量是异端邪说,但是目前的状态让它看起来像过度教条式的狂热而没有太多的研究相反.在我阅读的任何支持let的文章中,唯一的论点是对延迟加载和范围问题的一些吸引力,这两个问题在编写良好的测试中都是无关紧要的.

延迟加载在测试中似乎没有意义,因为它只在您不确定是否需要数据时才有用.如果是这种情况,为什么还要为这个测试首先构建数据呢?

如果你没有在你的测试中改变你的对象(提示:你不应该,那么将它存根),那么实例变量可能永远不会成为问题.如果是,耦合不是变量的错误,它就是测试本身.

TL; DR:有一种已知方法将let类型语句绑定到备用块区域吗?理想情况下,我想将它绑定到描述和上下文块以缓解此问题.

例:

describe 'Person' do
  local_bind let(:person) { Person.new(actual_data) }

  context 'It has no data' do
    local_bind let(:person) { Person.new(blank_data) }
    # tests
  end
end
Run Code Online (Sandbox Code Playgroud)

其中local_bind将let绑定到当前块上下文而不是它运行的示例.当然这是推测语法,但这里提供了一般性的想法.

这将允许我们声明一个对象用于块区域内的所有示例,这将大大减少let的示例仅仅是memoization的不良影响.

虽然这些问题不会明显地显示在基本对象上(50个调用*0.001实例化仍然相当快),但在更昂贵的问题上会变得明显可见(50个调用*0.1 = 5秒).

我已经看过很久以前就已经开始使用它了,当它们以某种方式进入规范帮助程序并在不良的性能抽象中随处可用时,你可以想象3,500个测试的测试套件如何能够快速弯曲到它的"膝盖".到目前为止观察到的差异是从JSON问题的8:15到1:57所花费的时间减少了75%,当我这样做时,让我确定我估计下降到20秒以下.努力获得证据.

ruby rspec ruby-on-rails let

5
推荐指数
1
解决办法
125
查看次数

标签 统计

let ×2

rspec ×2

ruby ×2

factory-bot ×1

mocking ×1

ruby-on-rails ×1