Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Rails, be a pal and reset the database between test suites

Work is transitioning from Rails 3 to Rails 4. Everything seems to be running more or less smoothly on the development side, but testing results in a multitude of varying failures when all suites - units, functionals, and integration - are run in one go with rake:test.

What's interesting is that running each of these suites individually produces no failures. This strongly suggests that the database is not resetting for our tests in Rails 4 quite the way it was in Rails 3.

I've tried overriding the rake:test task to execute db:test:prepare prior to running each suite, but this apparently doesn't do what I think it does, or rather, what I want it to do, which is to work with a fresh set of data for each test and therefore succeed or fail independently of every other test - the way it (was or should have been) in our Rails 3 setup.

Why is this happening? How might I fix it?

(Note that the testing framework is vanilla Rails with fixtures and the like. The testing failures we're getting are usually foreign key errors or failures for data to change in expected ways that don't show up when the DB is reset before a testing suite.)

EDIT:

Here are the changes I'm making to my Rakefile. The idea is to get rake:test to perform as it would in Rails 3, with the exception of properly resetting the database between unit, functional, and integration suites.

# /Rakefile

task :test => [];
Rake::Task[:test].clear
task :test do
    puts Rails.env
    if Rails.env == "test"
        puts "units"
        # Rake::Task["db:drop"].execute - results in 'test database not configured' error
        # Rake::Task["db:reset"].execute - results in 'relation 'table' does not exist' error
        Rake::Task["db:create"].execute
        Rake::Task["db:migrate"].execute
        Rake::Task["test:units"].execute
        puts "functionals"
        Rake::Task["db:schema:load"].execute
        Rake::Task["test:functionals"].execute
        puts "integration"
        Rake::Task["db:schema:load"].execute
        Rake::Task["test:integration"].execute
    end
end

EDIT 2:

Rails version 4.1.8

Here is my test_helper. I've omitted helper methods that don't work with our data since I'm probably not allowed to share them and they're irrelevant to how the testing database is loaded.

Note also that we have a custom schema.rb from which the testing data are generated, as well, since trying to create them from migrations does not support some of the custom functionality/behavior we want in the end product, like materialized views. Redacted stuff will be enclosed in <<>>.

#test_helper.rb
ENV["RAILS_ENV"] = "test"
require File.expand_path('../../config/environment', __FILE__)
require 'rails/test_help'
include ActionDispatch::TestProcess

class ActiveSupport::TestCase
  # Setup all fixtures in test/fixtures/*.(yml|csv) for all tests in alphabetical order.
  #
  # Note: You'll currently still have to declare fixtures explicitly in integration tests
  # -- they do not yet inherit this setting
  set_fixture_class <<cached_object>>: ResultsDb::<<DesiredObjectClass>>Cache
  fixtures :all

  # Add more helper methods to be used by all tests here...
  def reload_contig(contig_sym)
    contig = contigs(contig_sym)

    src = contig.src
    new_tig = Contig.new(
              org: contig.org,
              version: contig.version,
              size: contig.size,
              sha1: contig.sha1,
              active: contig.active,
              src_id: src.id,
              src_type: contig.src_type)

    new_tig.id = contig.id
    contig.destroy
    unless new_tig.save
      raise new_tig.errors.full_messages.inspect
    end
    src.contigs << new_tig
    src.save
    new_tig
  end

  def reload_coord(coord_sym)
      coord = coords(coord_sym)

      new_coord = Coord.new(
          :mapped_id => coord.mapped_id,
          :mapped_type => coord.mapped_type,
          :contig_id => coord.contig_id,
          :contig_type => coord.contig_type,
          :start => coord.start,
          :stop => coord.stop,
          :fwd_strand => coord.fwd_strand
      )
      new_coord.id = coord.id
      coord.destroy
      new_coord.save!
  end
end
like image 597
Vardarac Avatar asked May 26 '15 22:05

Vardarac


People also ask

How do I reset a Rails database?

db:reset: Resets your database using your migrations for the current environment. It does this by running the db:drop , db:create , db:migrate tasks. db:rollback: Rolls the schema back to the previous version, undoing the migration that you just ran. If you want to undo previous n migrations, pass STEP=n to this task.

What does Rails db test prepare do?

Specifically, rake db:test:prepare will do the following: Check for pending migrations and, load the test schema.

How do you regenerate a schema RB?

If you run a rake -T it will list all possible rake tasks for your Rails project. One of them is db:schema:dump which will recreate the schema.

What are integration tests rails?

While unit tests make sure that individual parts of your application work, integration tests are used to test that different parts of your application work together.


1 Answers

You might have a look at the DatabaseCleaner gem that is specifically designed to assist you with database consistency and cleanliness during testing in Rails.

I've only run into problems when my code bypasses ActiveRecord and manipulates the data directly. In all other cases this gem has worked very well for me for testing.

like image 165
David Hoelzer Avatar answered Nov 05 '22 18:11

David Hoelzer