Using instance_double in RSpec tests

Why use doubles in RSpec tests?

If you’re a Ruby programmer or work with Rails, it’s likely you’ll have designed tests using RSpec – the testing library for Rails, to test Ruby code. RSpec features doubles that can be used as ‘stand-ins’ to mock an object that’s being used by another object. Doubles are useful when testing the behaviour and interaction between objects when we don’t want to call the real objects – something that can take time and often has dependencies we’re not concerned with. For example, we may only need to mimic the behaviour of an object in a test. This is where doubles come in useful.

Let’s consider an example:

This test creates a Tutor double, which only knows about the information method. If we try to call college, we get an error that the Tutor double received an unexpected message. Unlike a real tutor object, we can’t call tutor.college on the double because it’s not set up to respond to the college method.

So shouldn’t we just set up the Tutor double to respond to college? We could, but we simply don’t need this extra code. In practical terms, to get tutor.college to return a value, we’d need to have a college table populated with data. But if our test only needs something that looks like a tutor and can access its information, then using a simple double, as in the above test, will achieve that goal.

Double trouble

But doubles can be controversial. It could be argued that using doubles to abstract away real implementations can cause problems, especially when something has changed in the described class that a double is mocking, e.g. if a method is modified.

In our example RSpec test, there are two classes – Tutor and Student. The relationship defines a student as having a tutor. When a new student is created, a tutor is passed in as well as the name. In this test, a double is used to mock out Tutor when testing the Student class. The test passes with 0 failures.

But what happens if we rename the information method to details in our code and change what the details method returns, but forget to update the test?

The test passes with 0 failures, but this isn’t accurate because the test no longer represents the Tutor class correctly. A good test tells us that the Tutor class has changed. In this example, we want the test to fail so we can fix it and accurately represent the tutor interface.

sb-tech-site-technology

When to use instance_double

This is where instance_double can be used to remedy the situation!

In RSpec 3.0 and higher, instance_double is an implementation of verifying doubles. Verifying doubles are defined in RSpec as “a stricter alternative to normal doubles that provide guarantees about what is being verified. When using verifying doubles, RSpec will check that the methods being stubbed are actually present on the underlying object, if it is available.”

Let’s look at how instance_double can help in our test:

All we’ve done is to use instance-double instead of double, replacing double(Tutor, information: 'Jane teaches Ruby.') with instance_double(Tutor, information: 'Jane teaches Ruby.'). The test now fails and it forces us to find out whether the information method is still appropriate to use on the Tutor double. In this case, it’s not. We need to update the Tutor double to use the details method instead.

Here’s the updated test, which now passes.

Conclusion

Using instance_double instead of RSpec’s regular double can ensure the real object and its double stay in sync.

Read more about instance_double in the RSpec documentation.

See our latest technology team opportunities

If you see a position that suits, why not apply today?

Cai Gao

This block is configured using JavaScript. A preview is not available in the editor.