Rspec should instance of
They may pass the instance variable to some other part of the app, which modifies the given value. This is where things go wrong, what the RSpec docs warn us about. If changing the instance variable is the problem, let's reassign it and see what happens in other specs.
In the example below the "spec 1" spec changes the instance variable to test a slightly different scenario. In this example "spec 2" does not fail, even though "spec 1"—which runs before "spec 2"—changes the instance variable. There was no need for us to reset the original value of the instance variable at the end of the spec even though we changed it. The way that RSpec runs the specs ensures that every spec uses the original instance variables.
Every spec in RSpec is its own Ruby class, in which the spec is performed. Before the spec class run, RSpec sets the instance variables from the before :context block on the spec class. When an instance variable is reassigned in a spec, it only reassigns it on that spec class instance. It doesn't not reassign the instance variable on the same scope as the before :context instance variables are stored, and so does not interfere with any other specs.
An example of how this looks can be found later on in this post. This behavior doesn't always quite work though. Let's see what happens if we use a bit more complex value. That way we know the limitations of using instance variables in RSpec. We will intentionally break the spec in this scenario. In "spec 1" we're testing a slightly different scenario again, modifying the value before running the assertion. Unlike before, the "spec 2" spec has now failed. It fails because the instance variable still has the value from the first spec.
State has leaked from "spec 1" into "spec 2". Let's look at how the values from these instance variables have moved between specs. Let's take a closer look at how RSpec handles instance variables for spec classes to see how this could break in our test suite. When RSpec runs specs in a context, it first runs the before :context blocks.
After a before :context block is executed RSpec then stores the list of the instance variables on the class it creates for the context. When RSpec then starts a spec in that context it creates a new class for that spec and sets instance variables of that context on the spec class.
Let's look at how this works using the same scenario from the second example, where we reassigned the instance variables. In the above example we generate a new instance of Client in each test before we make the assertion that it responds to the particular methods. There are some drawbacks to this implementation:.
RSpec, like other test frameworks, provides helper methods for test setup and test tear down for individual examples and groups of examples.
These helper methods are named before and after. Both of them accept an :each parameter to run once before each example, or :all to run once before all the examples:. Here before :each execute the code contained within the block do In this trivial example we could have used before :all and set up our client object once.
It is important to know that changes made within a before :all block will not be rolled back after tests. You can define a before and after within each describe or context block, allowing you to easily add setup and creation as necessary. Notice that both before :all helper methods executed prior each of the before :each helper methods. This is reverse for our after helper methods. RSpec may appear to be an altogether different language that is allowing you to embed Ruby within it to exercise your code, but it is not.
It is just Ruby! Then, when we write examples about that method, we wrap them in a describe block with the name of the method prefixed with a to indicate it is an instance method:.
We saved ourselves the hassle of having to generate a Client each execution with the before :all , but we still have the instance variable client throughout our examples. RSpec has the convention that when you call should without an explicit receiver it is assumed that you mean to make an assertion against the subject under test. Instead we can by-pass this and set the method to true automatically in our double.
Here we have used the let method to set the double we have created to the variable :owner. Next, we need to create an instance of our Pet so that we can call the necessary method! You can also set your subject at the top so that the expect method is a little cleaner.
Both of these will give you a passing test. There are some drawbacks to using doubles though, albeit minor:. However, if you do want to your tests to be more stable and well-constructed, as well as taking a small speed hit. I would recommend using Instance Doubles in your tests instead! This is similar to a double except it will verify the interface of a double to make sure it matches the class or instance it is mocking. This makes your tests a little bit stricter as you have to mock an object correctly.
The instance method can only define methods that are on the class it is replicating. Firstly, make sure you pass in an argument to your instance double verifying which class RSpec will be making an instance object of.
It will even test if you are passing in the correct amount of arguments, if any at all. But as we can see RSpec checks the actual method and compares. Then gives you an error saying that specific method was not expecting any arguments! So it will also check their implementations and arguments.
This ensures our doubles are as similar or as close to our class as possible. So, to correctly implement an instance variable we must stick to the same methods the class provides. Now we must correctly create an instance double.
0コメント