即日起在codingBlog上分享您的技术经验即可获得积分,积分可兑换现金哦。

当使用RSpec let()?

栈溢出 Bryan Ash 3428℃ 0评论
本文目录
[隐藏]

1.原始问题:When to use RSpec let()?

I tend to use before blocks to set instance variables. I then use those variables across my examples. I recently came upon let(). According to RSpec docs, it is used to

… to define a memoized helper method. The value will be cached across multiple calls in the same example but not across examples.

How is this different from using instance variables in before blocks? And also when should you use let() vs before()?

2.被采纳答案

I always prefer let to an instance variable for a couple of reasons:

  • Instance variables spring into existence when referenced. This means that if you fat finger the spelling of the instance variable, a new one will be created and initialized to nil, which can lead to subtle bugs and false positives. Since let creates a method, you’ll get a NameError when you misspell it, which I find preferable. It makes it easier to refactor specs, too.
  • A before(:each) hook will run before each example, even if the example doesn’t use any of the instance variables defined in the hook. This isn’t usually a big deal, but if the setup of the instance variable takes a long time, then you’re wasting cycles. For the method defined by let, the initialization code only runs if the example calls it.
  • You can refactor from a local variable in an example directly into a let without changing the
    referencing syntax in the example. If you refactor to an instance variable, you have to change
    how you reference the object in the example (e.g. add an @).
  • This is a bit subjective, but as Mike Lewis pointed out, I think it makes the spec easier to read. I like the organization of defining all my dependent objects with let and keeping my it block nice and short.

3.其他高票答案

3.1.第1个答案

The difference between using instances variables and let() is that let() is lazy-evaluated. This means that let() is not evaluated until the method that it defines is run for the first time.

The difference between before and let is that let() gives you a nice way of defining a group of variables in a ‘cascading’ style. By doing this, the spec looks a little better by simplifying the code.

3.2.第2个答案

I have completely replaced all uses of instance variables in my rspec tests to use let(). I’ve written a quickie example for a friend who used it to teach a small Rspec class: http://ruby-lambda.blogspot.com/2011/02/agile-rspec-with-let.html

As some of the other answers here says, let() is lazy evaluated so it will only load the ones that require loading. It DRYs up the spec and make it more readable. I’ve in fact ported the Rspec let() code to use in my controllers, in the style of inherited_resource gem. http://ruby-lambda.blogspot.com/2010/06/stealing-let-from-rspec.html

Along with lazy evaluation, the other advantage is that, combined with ActiveSupport::Concern, and the load-everything-in spec/support/ behavior, you can create your very own spec mini-DSL specific to your application. I’ve written ones for testing against Rack and RESTful resources.

The strategy I use is Factory-everything (via Machinist+Forgery/Faker). However, it is possible to use it in combination with before(:each) blocks to preload factories for an entire set of example groups, allowing the specs to run faster: http://makandra.com/notes/770-taking-advantage-of-rspec-s-let-in-before-blocks

3.3.第3个答案

It is important to keep in mind that let is lazy evaluated and not putting side-effect methods in it otherwise you would not be able to change from let to before(:each) easily.
You can use let! instead of let so that it is evaluated before each scenario.

3.4.第4个答案

In general, let() is a nicer syntax, and it saves you typing @name symbols all over the place. But, caveat emptor! I have found let() also introduces subtle bugs (or at least head scratching) because the variable doesn’t really exist until you try to use it… Tell tale sign: if adding a puts after the let() to see that the variable is correct allows a spec to pass, but without the puts the spec fails — you have found this subtlety.

I have also found that let() doesn’t seem to cache in all circumstances! I wrote it up in my blog: http://technicaldebt.com/?p=1242

Maybe it is just me?

转载请注明:CodingBlog » 当使用RSpec let()?

喜欢 (0)or分享 (0)
发表我的评论
取消评论

*

表情