Article

Taking the test trash out with DatabaseCleaner and RSpec

So you’ve built an awesome new application; created a bunch of zoom zoom zoom features accompanied with a safety net of tests to support it all – life is good! You decide to give your tests one last spin before deploying your application to the production server, but your happiness is short lived when you start to see some weird inconsistencies in your results. What to do? Do I need to call Captain Hindsight? No, it’s quite simple really, start using DatabaseCleaner. DatabaseCleaner is collection of strategies used for cleaning your database in Ruby. It’s designed to ensure a clean database state before triggering a test example; preventing any data left over from any previous test examples contaminating your results. In this post I will be explaining how to use DatabaseCleaner with RSpec, however it can configured for Cucumber and Minitest if required. Let’s get started! First of all you will need to update the following line in your spec_helper.rb*:

To:

This will disable the rspec-rails standard behaviour of wrapping each of your test examples within a transaction – your DatabaseCleaner configuration will not work if this has not been updated. Next step will be to create your DatabaseCleaner configuration file. When installing RSpec, it tries to keep your test suite configration clean by creating a rule within spec_helper.rb* to retrieve custom configuration files from spec/support – I would advise following this design pattern and creating your config file in spec/support/database_cleaner.rb. Your config file should look like the following:

This may look all rather confusing, so I’ll take you through each block and provide more detail.

This configuration block is the wildling giant of your DatabaseCleaner configuration, smashing through your test database and clearing out all the trash – including interrupted or poorly-written tests.

Before each test example, this will set the default cleaning strategy to transaction. Transactions are the F1 racing car of the database strategy world, very fast, however they are only usable when the entire test runs in the RSpec process.

This configuration block is a special case which is only run when js has been set to true in the test example. They are generally used for Capybara tests which use a javascript headless webkit such as Selenium or PhantomJS. For these types of tests, the transaction cleaning strategy does not play well, so we are forced to use truncation instead.

These configuration blocks are executed before and after each test example. The first executes the database cleaning strategy declared in the above configuration, whereas the second grabs the nearest Dyson vacuum and cleans up all the trash left behind after the test has completed.

Sounds good, but I’m still getting inconsistencies?!

The DatabaseCleaner is great at doing it’s job, but if the tests are poorly-written and do not comply with the configuration rules outlined above, inconsistencies can still arise in your test suite.

I recently had an issue when building up a 400+ test suite for my open source ecommerce platform, Trado. The individual spec files were running successfully, however when I ran the test suite as a whole, inconsistent errors started to surface. This was a clear indication that not all my tests were using the DatabaseCleaner to clear out the redundant test trash; a quick glance at my codebase quickly found the cause of my problem:

Can you notice the bug? If we check back to our DatabaseCleaner config, we are starting and running the cleaner either side of the example with a before(:each) and after(:each) hook. Whereas in the above example I have used before(:all), meaning the records instantiated within the hook are ignored when cleaning out the database. In future I need to ensure I’m using before(:each), let() or local variables when creating records, to prevent test data being left in the database and spilling over into other test examples.

Hopefully this helps you to solve any inconsistencies and keep you on the path to a complex, thorough test suite!

* modify the rails_helper.rb file instead if using rspec-rails 3+

01st July 2014

Any thoughts?

Your email address will not be published. Required fields are marked *

*

CAPTCHA * Time limit is exhausted. Please reload CAPTCHA.

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code class="" title="" data-url=""> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong> <pre class="" title="" data-url=""> <span class="" title="" data-url="">