Here is a bit of code from M Hartl's Ruby on Rails Tutorial. Can anyone explain why an instance variable (@user) is necessary and why not use a local variable. Also, since instance variables are supposed to be the variables in the instance of a class, which class is @user instantiated from?
require 'spec_helper'
describe User do
before { @user = User.new(name: "Example User", email: "[email protected]") }
subject { @user }
it { should respond_to(:name) }
it { should respond_to(:email) }
end
If you want to set a controller or view's instance variables in your RSpec test, then call assign either in a before block or at the start of an example group. The first argument is the name of the instance variable while the second is the value you want to assign to it.
You can't mock an instance variable. You can only mock methods. One option is to define a method inside OneClass that wraps the another_member , and mock that method. However, you don't have to, there is a better way to write and test your code.
(:let) is lazily evaluated and will never be instantiated if you don't call it, while (:let!) is forcefully evaluated before each method call.
let generates a method whose return value is memoized after the first call. This is known as lazy loading because the value is not loaded into memory until the method is called. Here is an example of how let is used within an RSpec test. let will generate a method called thing which returns a new instance of Thing .
Use of a local variable in that instance would mean that its scope would be restricted to the before
and hence result in an error. The @user
is of type User but is an instance variable of the describe
block. Rspec has some magic that at run-time makes a class out of each describe
block. Each example (it
block) ends up being a subclass of said class. Class inheritance lets the examples see @user
.
Edited 2017-05-14
Linked blog post is no longer available. Updating with Wayback Machine link + inlining relevant section here.
Note that this is considered an anti-pattern as detailed in this blog post. Use let
instead.
let
has the following advantages:
You can't use a local variable because a local variable exists only in the scope of the local method. before
, subject
and it
generates different scopes within the same class.
The following code
before { user = User.new(name: "Example User", email: "[email protected]") }
will raise an undefined variable when you call it in
subject { user }
The instance @user
is an instance of the class User
(after all, you create it with User.new
).
However, instead of instance variables you might want to use the let
command. Also, if you define
subject { User.new(name: "Example User", email: "[email protected]") }
the use of before
is not required. You'll also get the extra benefit to get a subject
method available to access the instance, equal to define let(:subject)
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With