test_seeds

Test Seeds allow efficient usage of object factories (like Factory Girl) in tests. Instead of creating objects for similar scenarios in each test case, Test Seeds start a db transaction for each test file, create all the common objects once, and then uses db savepoints for each test case allowing for the common objects to be re-used.

Description

Fixtures are a great way to get started. However, as your application becomes more complex, fixtures become a nightmare to manage and maintain. To alleviate this problem, people have flocked to object factories which allow creating complex testing scenarios right next to the code that tests those scenarios. Often similar scenarios are needed for a set of tests and the following pattern emerges,

class TestSomething < ActiveSupport::TestCase
  setup :create_scenario

  def create_scenario
    @object_1 = ...create AR objects...
    @object_2 = ...create AR objects...
    @object_3 = ...create AR objects...
  end

  def test_case_1
  end

  ...

  def test_case_N
  end

end

Sometimes creating the scenario in the setup callback, create_scenario is called by tests directly as needed. Either way, the problem is that create_scenario is called multiple times and creating objects via ActiveRecord is very slow. Test Seeds addresses this problem.

How It Works

Transactional fixtures work as follows,

test file do
  load fixtures
  transaction do
    test case 1
  end
  transaction do
    test case 2
  end
  transaction do
    test case 3
  end
end

Test Seeds piggy backs on the transaction fixtures functionality. Test Seeds load fixtures into the database in the same way but then start a db transaction for the duration of the test file. Any objects for the common scenarios are then created and inserted into the database. Test Seeds then execute each test case within a context of a db savepoint (or nested db transactions). This allows test seeds to be inserted into the database once and then re-used for each test case that needs it. Here is the pseudo code,

test file do
  load fixtures
  transaction do
    load seeds
    savepoint do 
      test case 1
    end
    savepoint do 
      test case 2
    end
    savepoint do 
      test case 3
    end
  end
end

How To Use

There are two main ways of using Test Seeds. The first way makes all the seeds available to all the tests,

class TestSomething < ActiveSupport::TestCase
  include TestSeeds

  seeds do
    @object_1 = ...create AR objects...
    @object_2 = ...create AR objects...
    @object_3 = ...create AR objects...
  end

  def test_case_1
    # @object_1, @object_2, and @object_3 are available here
  end

  ...

  def test_case_N
    # @object_1, @object_2, and @object_3 are available here
  end

end

Alternatively, you can be more selective which seeds go with which test cases,

class TestSomething < ActiveSupport::TestCase
  include TestSeeds

  seeds(:scenario_a) do
    @object_a1 = ...create AR objects...
    @object_a2 = ...create AR objects...
    @object_a3 = ...create AR objects...
  end

  seeds(:scenario_b) do
    @object_b1 = ...create AR objects...
    @object_b2 = ...create AR objects...
    @object_b3 = ...create AR objects...
  end

  def test_case_1
    setup_seeds(:scenario_a)
    # @object_a1, @object_a2, and @object_a3 are available here
  end

  def test_case_2
    setup_seeds(:scenario_b)
    # @object_b1, @object_b2, and @object_b3 are available here
  end

  def test_case_3
    setup_seeds(:scenario_a, :scenario_b)
    # @object_a1, @object_a2, and @object_a3 are available here
    # @object_b1, @object_b2, and @object_b3 are available here
  end

end

Contributing to test_seeds

  • Check out the latest master to make sure the feature hasn’t been implemented or the bug hasn’t been fixed yet

  • Check out the issue tracker to make sure someone already hasn’t requested it and/or contributed it

  • Fork the project

  • Start a feature/bugfix branch

  • Commit and push until you are happy with your contribution

  • Make sure to add tests for it. This is important so I don’t break it in a future version unintentionally.

  • Please try not to mess with the Rakefile, version, or history. If you want to have your own version, or is otherwise necessary, that is fine, but please isolate to its own commit so I can cherry-pick around it.

Copyright © 2011 Paul Kmiec. See LICENSE.txt for further details.