How to speed up your RSpec test suite

As developers at FindHotel, we write code following the Test Driven Development (TDD) methodology, which requires you to write tests before the actual code. This is nothing new in the development world, even though most of the people find it hard to stick with this approach as it's considered time-consuming. We usually argue that the time invested into testing first saves you plenty of time that otherwise you will put into debugging problems in our production environment.

Long story short, we write tests. A lot of tests. In fact, enough tests that eventually we reached the point where running tests as often as TDD requires became an expensive task.

Our test suite nowadays consists of 2600+ tests and our machines, although equipped with SSD disks and four i7 HT cores, would take almost 4 mins to run them all sequentially.

rspec

Now, 4 mins is a lot of time when you want to run the tests almost every time you make a change to your code. Furthermore, when the number of tests is big (and you know it'll keep growing), you will always be slowed down by serial execution, no matter how fast your machine runs code.

One might argue that you don't need to run all the tests every single time, and that's indeed true. On the other hand, if the time for running all the tests was short enough, wouldn't it be nicer (and safer) to just run the entire test suite, typing the same command all the times without have to think about it?

Test parallelization

Luckily, there's a simple yet effective solution to this problem: parallelization.

After a bit of research, we came across parallel_tests, a Ruby gem which splits tests into even groups (by number of lines or runtime) and runs each group in a single process with its own database.

Essentially you can spread the execution of tests across your N cores, theoretically reducing the execution time by N times^(*)^. Also, the gem supports a variety of Ruby test tools, like RSpec, Test::Unit, Cucumber, and Spinach.

^(*)^ This is not necessarily a linear relationship, as a number of factors can influence such outcome (process booting, not even split of tests, etc..).

In order to use it, you need first to install the gem adding it to your Gemfile:

gem "parallel_tests", group: :development

In order to achieve parallelization, you will need as many test databases as the number of cores on your machine; the gem provides a task for creating such databases:

rake parallel:prepare

Then you can run the tests (in our case RSpec) by doing:

rake parallel:spec

Let's see how the same machine handles the very same test suite in parallel:

parallel_4

It only takes 56 seconds to run the entire test suite, brilliant!

And there's more: the time needed to execute the test suite will grow much slower than using sequential test execution.

Try it yourself!

If you want to give the parallel_tests gem a try in your Rails project, follow the instructions and get your tests running at the speed of light!