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()
?
I always prefer let
to an instance variable for a couple of reasons:
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. 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. @
). let
and keeping my it
block nice and short. 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.
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
链接地址: http://www.djcxy.com/p/59300.html上一篇: rspec如何运行单个测试?
下一篇: 何时使用RSpec let()?