Nebojša Stričević wrote this on October 10, 2012

Cleaning up after before(:all) blocks

Recently we added a project that is active since 2007 to Semaphore. Quickly after that, some RSpec scenarios started failing randomly.

After quick inspection we saw a number of before(:all) blocks that were not cleaning the database after itself.

The problem

In a typical scenario, test examples are run in a transaction. The problem lies in the fact that data created in a before(:all) block is NOT rolled back after tests are done (RSpec/Transactions).

Every before(:all) block should have an after(:all) block that will clean a database. But, sometimes you don’t really know all the records that are created in a before(:all) block.

The project was using FactoryGirl to create records in tests. And with FactoryGirl’s support for creating associated object, it’s easy to create few more records that you are not aware of. Although that is a sign of a smell in your tests, sometimes you need a quick fix to continue your work.

Quick fix

The quick fix that we tried was to substitute all before(:all) blocks with before(:each) blocks that are run in a transaction. The fix worked and there were no more randomly failing tests, but time to run the test suite increased significantly.

The real solution

If you use Database Cleaner you already have the tool that can save your day. A usefull feature of Database Cleaner allows you to clean a database with a strategy that you choose:

after(:all) do
  DatabaseCleaner.clean_with(:truncation)
end

This will clean the database with truncation strategy. You should experiment with different strategies to find the one that works best for you.

In this case it was easy to blame Semaphore for failing tests, but the thing is that developers rarely run the whole test suite since that took around 30 minutes to complete. So after you add a project to a CI service you should expect that your test suite will be executed a number of times each day, instead once or twice a week. In this kind of scenario, you should expect that all deficiencies of the test suite will quickly be revealed, and it’s worth taking some time to optimize.

comments powered by Disqus


Suggested Reads

Inject is a fundamental building block

Inject is one of the fundamental, and most versatile constructs available in functional languages. It can be used to implement map, select, max, all? and a bunch of other iteration related methods. Unfortunately, many programmers are not aware of its awesome powers. This article is here to improve this fact.

Contact

Rendered Text is a software company. For questions regarding Semaphore, please visit semaphoreci.com. Otherwise, feel free to get in touch any time by sending us an email.

Rendered Text
Svetozara Miletica 10
21000 Novi Sad
Serbia