Clearing the test database between unit and functional tests in Rails (factory_girl)
Asked Answered
O

6

21

Recently I switched from fixtures to factory_girl to test my Ruby on Rails application. If I run rake test:units, to run the tests in my /units directory, they all run perfectly. The same is true if I run my functional tests (in my /functional directory) with rake test:functionals.

However, if I simply run rake test, to run both my unit and functional tests together, my validation fails on the second group of tests (functional, in this case), with the message "Validation failed: Name has already been taken."

I believe this is caused by the functional tests creating objects with the same parameters as the objects that were created in the unit tests -- leading me to believe that the test database isn't cleared in between the unit and functional tests.

I use factory_girl's sequencing to have unique attributes for objects, which means that factory_girl is being reset between tests, while the database is not. What can I do to solve this problem? Is there a way to clear the database between my two test packages?

Oliviaolivie answered 27/7, 2009 at 16:43 Comment(1)
did you find any solution to this problem? I have the exact same. For some reason factory girl sequences is reset between functional and unit tests.Sonnnie
W
12

Try writing this in your test/test_helper.rb

eval IO.read(File.expand_path(File.dirname(__FILE__) + "/../Rakefile"))
class Test::Unit::TestCase
 ....
 #db:test:prepare won't work, don't know why,
 #as DROP DATABASE won't execute (me on PostgreSQL).
 #even if I write,
 #ActiveRecord::Base.connection.disconnect!
 Rake::Task["db:reset"].invoke
end

It's not a recommended solution. It makes tests slower, but it works.

Welsh answered 28/7, 2009 at 2:32 Comment(2)
Perfect, thanks! I don't have too many tests at this point, so speed isn't a big issue yet.Oliviaolivie
This works for me also! Does somebody know why is this happening? I have been using factories for some time and this never has been a problem. Seems that updating from factory-girl to factory-girl-rails is the cause of the problem... I'm using rails 3.2.2Bellyful
A
14

A command line solution to clear (reconstruct) test database:

rake db:test:prepare
Avidity answered 17/3, 2013 at 21:4 Comment(0)
W
12

Try writing this in your test/test_helper.rb

eval IO.read(File.expand_path(File.dirname(__FILE__) + "/../Rakefile"))
class Test::Unit::TestCase
 ....
 #db:test:prepare won't work, don't know why,
 #as DROP DATABASE won't execute (me on PostgreSQL).
 #even if I write,
 #ActiveRecord::Base.connection.disconnect!
 Rake::Task["db:reset"].invoke
end

It's not a recommended solution. It makes tests slower, but it works.

Welsh answered 28/7, 2009 at 2:32 Comment(2)
Perfect, thanks! I don't have too many tests at this point, so speed isn't a big issue yet.Oliviaolivie
This works for me also! Does somebody know why is this happening? I have been using factories for some time and this never has been a problem. Seems that updating from factory-girl to factory-girl-rails is the cause of the problem... I'm using rails 3.2.2Bellyful
H
4

A rails plugin called "override_rake_task" could be used to override Rake task "test" which is defined inside if Rails gem. This is a very simple task that executes 3 other tasks one after another: test:units, test:functionals and test:integration. You could include the execution of "db:test:purge" task to clear the test DB before executing test:functionals.

Apparently if you are not using this plugin and if you define a task in your rails application with the same name, rake would execute both tasks: the default and yours.

Hainan answered 27/7, 2009 at 16:57 Comment(2)
Is there a way to execute db:test:purge between the unit and functional tests without overriding the default rake tasks?Oliviaolivie
Yes, you could probably do the same thing without a plugin by first removing the default task and adding a new one with the same code + "db:test:purge": "remove_task :test" then "task :test do ... end". I saw this here: taknado.com/2007/7/30/overriding-rake-tasksHainan
H
2

The above solutions didn't work for me. If you are trying to reach out to an external database running unit tests can give some weird errors. For some reason they do not get cleared after running the test so you have to run rake db:test:purge after running the unit tests. Put this in your Rakefile and it should fix it.

Rake::Task["db:test:prepare"].enhance do
  Rake::Task["db:test:purge"].invoke
end
Hejaz answered 31/10, 2009 at 4:15 Comment(0)
A
1

I ran into this problem on my machine. I was getting test failures, from validation problems because the database wasn't properly being reset between tests. Some back story about my situation:

-I had a linux box, and was running code, that I knew should pass the tests.
-I bought a Mac with Lion installed and attempted to get my code running on that machine.
-I installed mysql from source

Everything installed fine. My database worked, and rails could access it. When I ran tests however, I ran into the same problem. I came across this post, and tried both the proposed solutions (even though it didn't seem like a code issue, it seemed like a configuration problem since rake ran fine on my linux box). None of the solutions works.

I removed mysql:

sudo rm /usr/local/mysql
sudo rm -rf /usr/local/mysql*
sudo rm -rf /Library/StartupItems/MySQLCOM
sudo rm -rf /Library/PreferencePanes/My*
sudo rm -rf /Library/Receipts/mysql*
sudo rm -rf /Library/Receipts/MySQL*
sudo rm /etc/my.cnf
sudo rm /usr/local/bin/mysql*

I reinstalled mysql with homebrew instead of manually doing it from source (this step was courtesy of a co-worker's advice):

export PATH="/usr/local/bin:/usr/local/sbin:/usr/local/mysql/bin:$PATH"
brew install https://github.com/adamv/homebrew-alt/raw/master/versions/mysql51.rb
unset TMPDIR
mysql_install_db

I then re-ran rake, and all the tests passed. If anyone is on Lion, built mysql from source, and ran into this problem, this might be a solution.

Airborne answered 6/10, 2011 at 22:21 Comment(0)
E
0

DB cleaner is a pretty nice gem specifically for cleaning between tests. It gives a few options including wrapping every test in a transaction and rolling back, truncating the table, and deleting.

It also supports multiple ORMS in case you're not using/ using more than active record.

The documentation is pretty good and includes examples of using it with MiniTest, Rspec, and Cucumber.

https://github.com/bmabey/database_cleaner

Ectopia answered 8/6, 2014 at 3:13 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.