Transactional dynamic test data for rails


Fixture replacements like Factory Girl are great, but when you have to set up complex test data or use Shoulda and your test records are created for each should block, you’ll get a huge performance hit.

Rails’ Fixtures are loaded only once and then rolled back via database transaction after every test - why not leverage this for your Factory-built test data as well? Transactionata allows you to do so:

class UserTest < ActiveSupport::TestCase
  test_data do
    Factory.create(:user, :login => 'colszowka')
    # super-complex, time consuming, web-service-hooked-up test data setup continues

  should "destroy a User" do
    assert User.('colszowka').destroy

  should "have a User" do
    assert User.('colszowka')

  context "The User" do
    subject { @user ||= User.find_by_login!('colszowka') }

    should "not be a new record" do
      assert !subject.new_record?

This will run the code block given to test_data alongside Fixtures and therefore ‘protect’ your data using Rails built-in fixture transactions, giving you huge performance gains if you’re using factories a lot.

For the (FactoryGirl/Shoulda-heavy) Ruby Toolbox 2 test suite, the time for a complete test run went from 5 minutes to 50 seconds by just moving test data generation into centralized blocks for each test case using Transactionata.


Add it to your Gemfile and bundle install.

gem 'transactionata', :group => :test

Then move test data generation to a test_data block as shown above, using finders instead of creating the records in the setup/subject blocks.

Of course, all of this is completely applicable to default Ruby/Rails unit tests, you don’t have to use Shoulda for transactional data setup to work.

Please note that you’ll have to have fixture files for the models you’re using transactionata for. They can be empty, but they have to be in place so Rails’ Fixture loading mechanism will purge the database tables between multiple test cases.


Transactionata’s test suite currently runs against Rails 2.3.10 and 3.0.4 on Ruby 1.9.2, 1.8.7 and REE. Since no black magic is involved, it should work on other platforms and versions as well.

Copyright © 2011 Christoph Olszowka. See LICENSE for details.