Let’s Test It Well: Simply and Smartly
mock_model
and stub_model
is, how to use shared_context
and shared_examples
, etc.If you are fond of testing, just like our Ruby Developer Nastia Shaternik, you’ll probably be interested to read her post about using RSpec. There, she dwells on how some RSpec features that are not commonly used can help you to simplify testing and make tests clearer.
This article explains how to make tests readable as short documentation and how using mock_model can make your tests run faster. In addition, we exemplify the usage of RSpec’s built-in expectations, two strategies of sharing the same data among different examples, etc.
Tests as specification
I’m really fond of tests, which can be read as short documentation and expose the application’s API. To help you to cope with it, run your specs with the --format d[ocumentation]
option. The output will be printed in a nested way. If you don’t understand what your code can do, you should rewrite your tests. In order not to write RSpec options every time when running specs, create a .rspec
configuration file in your home or application directory. (Options that are stored in ./.rspec
take precedence over options stored in ~/.rspec
, and any options declared directly on the command line will take precedence over those in either file.) The .rspec
file will look as shown below.
RSpec’s built-in expectations
Avoid using !=
and remember about should_not
. To test the actual.predicate?
methods, use actual.should be_[predicate]
.
Please also use collection’s matchers.
mock_model
vs. stub_model
By default, mock_model
produces a mock that acts like an existing record (persisted()
returns true). The stub_model
method is similar to mock_model
except that it creates an actual instance of the model. This requires that the model has a corresponding table in the database. So, the main advantage is obvious, tests written with mock_model
, will run faster. Another advantage of mock_model
over stub_model
is that it’s a true double, so the examples are not dependent on the behavior/misbehavior or even the existence of any other code.
Usage of the mock_model
method is quite simple and is illustrated below.
subject
and it {}
In an example group, you can use the subject
method to define an explicit subject for testing by passing it a block. Now, you can use the it {}
constructions to specify matchers. It’s just concise!
DRY!ness
There are two strategies—shared context and shared examples—to share the same data among different examples.
Shared context
Use shared_context
to define a block that will be evaluated in the context of example groups by employing include_context
. You can put settings (something in the before
/after
block), variables, data, and methods. All the things you put into shared_contex
will be accessible in the example group by name.
Below, you can see how to define shared_context
.
Here is how you use shared_context
.
Shared examples
Shared examples are used to describe a common behavior and encapsulate it into a single example group. Then, examples can be applied to another example group.
This is how you define shared_examples
.
Below, you can see how to use shared_examples
.
For more information about RSpec, you can consult with the official documentation. The book by RSpec’s creator David Chelimsky will also be helpful. Or, you can opt for these guides on Better Specs.