我倾向于在块之前使用来设置实例变量.然后,我在我的示例中使用这些变量.我最近遇到了let().根据RSpec文档,它习惯了
...定义一个memoized帮助方法.该值将在同一示例中的多个调用之间缓存,但不跨示例缓存.
这与在块之前使用实例变量有什么不同?还有什么时候你应该使用let()vs before()?
Myr*_*ton 600
我总是喜欢let一个实例变量,原因有两个:
nil,这可能会导致微妙的错误和误报.既然let创建了一个方法,那么NameError当你拼错它时你会得到一个,我认为这更好.它也使得重构规范变得更容易.before(:each)钩子将每个例子之前运行,即使例如不使用任何在钩定义的实例变量.这通常不是什么大问题,但如果实例变量的设置需要很长时间,那么你就是在浪费周期.对于定义的方法let,初始化代码仅在示例调用它时运行.@).let并保持我的it块很好和简短.相关链接可在此处找到:http://www.betterspecs.org/#let
Mik*_*wis 82
使用实例变量和之间的差异let()在于,let()是懒评估.这意味着let()在第一次运行它定义的方法之前不会对其进行求值.
之间的区别before和let是let()给你定义的"级联"的风格一组变量的一个很好的方式.通过这样做,通过简化代码,规范看起来更好一些.
Ho-*_*iao 17
我在我的rspec测试中完全替换了实例变量的所有用法以使用let().我为一个用它来教一个小型Rspec类的朋友写了一个简短的例子:http://ruby-lambda.blogspot.com/2011/02/agile-rspec-with-let.html
正如其他一些答案所说的那样,let()是惰性求值的,因此它只会加载需要加载的那些.它会破坏规范并使其更具可读性.事实上,我已经将我的控制器中使用的Rspec let()代码移植到了inherited_resource gem的样式中.http://ruby-lambda.blogspot.com/2010/06/stealing-let-from-rspec.html
除了懒惰的评估,另一个优点是,结合ActiveSupport :: Concern,以及load-everything-in规范/支持/行为,您可以创建特定于您的应用程序的自己的spec mini-DSL.我已经编写过针对Rack和RESTful资源进行测试的文章.
我使用的策略是Factory-everything(通过Machinist + Forgery/Faker).但是,可以将它与before(:each)块结合使用,为整个示例组预加载工厂,从而使规范运行得更快:http://makandra.com/notes/770-taking-advantage -of-rspec的-S-LET-在前方的块
ift*_*itz 11
这里有不同的声音:使用了 5 年 rspec 我不太喜欢let。
当设置中声明的某些内容实际上并不影响状态,而其他内容则影响状态时,就很难对设置进行推理。
最终,出于沮丧,有人只是改变let了let!(同样的事情,没有懒惰的评估)以使他们的规范工作。如果这对他们来说有效,一个新的习惯就会诞生:当一个新的规范被添加到一个旧的套件中并且它不起作用时,作者尝试的第一let件事就是在随机调用中添加刘海。
很快所有的性能优势都消失了。
我宁愿向我的团队教授 Ruby,也不愿教 rspec 的技巧。实例变量或方法调用在本项目和其他项目中的任何地方都很有用,let语法仅在 rspec 中有用。
let()对于我们不想一遍又一遍创建的昂贵依赖项很有用。它还与 配合得很好subject,让您可以减少对多参数方法的重复调用
多次重复的昂贵依赖项和具有大签名的方法都是我们可以使代码变得更好的点:
在所有这些情况下,我可以使用 rspec 魔法的舒缓膏来解决困难测试的症状,或者我可以尝试解决原因。我觉得过去几年我在前者上花了太多时间,现在我想要一些更好的代码。
回答原来的问题:我宁愿不这样做,但我仍然使用let. 我主要使用它来适应团队其他成员的风格(似乎世界上大多数 Rails 程序员现在都深入了解他们的 rspec 魔法,所以这种情况很常见)。有时,当我向一些我无法控制的代码添加测试,或者没有时间重构为更好的抽象时,我会使用它:即,当唯一的选择是止痛药时。
通常,它let()是一种更好的语法,它可以节省您@name在整个地方键入符号.但是,请注意!我发现let()还引入了微妙的错误(或者至少是头部划痕),因为变量在您尝试使用之前并不存在...告诉故事标志:如果在添加puts之后let()看到变量是正确的则允许规范传递,但没有puts规范失败 - 你已经找到了这个微妙.
我也发现let()在所有情况下似乎都没有缓存!我在我的博客中写了这篇文章:http://technicaldebt.com/?p = 1242
也许只是我?
let是功能性的,因为它本质上是一个Proc.也是它的缓存.
我得到的一个问题是......在一个正在评估变化的Spec块中.
let(:object) {FactoryGirl.create :object}
expect {
post :destroy, id: review.id
}.to change(Object, :count).by(-1)
Run Code Online (Sandbox Code Playgroud)
你需要确保let在你的期望区之外打电话.即你FactoryGirl.create在let块中调用.我通常通过验证对象是否持久来做到这一点.
object.persisted?.should eq true
Run Code Online (Sandbox Code Playgroud)
否则,当let第一次调用块时,由于延迟实例化,实际上将发生数据库更改.
更新
只需添加备注.小心打码高尔夫或在这种情况下rspec高尔夫与这个答案.
在这种情况下,我只需要调用一个对象响应的方法.所以我_.persisted?在对象上调用_方法作为它的真实.我要做的就是实例化对象.你可以打电话给空吗?还是没有?太.关键不在于测试,而是通过调用它来引导生命.
所以你无法重构
object.persisted?.should eq true
Run Code Online (Sandbox Code Playgroud)
成为
object.should be_persisted
Run Code Online (Sandbox Code Playgroud)
因为对象尚未实例化...它的懒惰.:)
更新2
利用让!即时对象创建的语法,应该完全避免这个问题.注意虽然它会打败很多非撞击让懒惰的目的.
此外,在某些情况下,您可能实际上想要利用主题语法而不是let,因为它可能会为您提供其他选项.
subject(:object) {FactoryGirl.create :object}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
108709 次 |
| 最近记录: |