Rails fixtures with models using set_table_name
If you have a model that uses set_table_name you may hit a snag when trying to use fixtures and unit tests. The solution is twofold: name the fixture file using the legacy table name, and use the set_fixture_class method in your unit test. I coudn’t find this method mentioned in Agile Web Development with Rails, and there’s only a brief mention on the rubyonrails.com site. Still, some web searches turned up the answers.
Here is a simple example:
We’ll start with a table named
libris_book that contains book entries. The name libris_book won’t really fly with the Rails pluralized table name approach. It’s easy, however, to fix that disconnect in the model:
class Book < ActiveRecord::Base set_table_name 'libris_book' end
Let’s take a look at our data:
~/src/libris$ script/console Loading development environment. >> Book.count => 1230
Good enough. Now, we’ll be good little coders and write some unit tests using fixtures. We’ll create a fixture file and our test class:
test_book: title: Life in Lawrenceburg author: Darren Day
require File.dirname(__FILE__) + '/../test_helper' class BookTest < Test::Unit::TestCase fixtures :books def test_fixtures assert_equal(2,Book.count) test_book = books(:test_book) end end
Looks good, but it won’t work!
~/src/libris$ rake test (in /home/darrend/src/libris) /usr/local/bin/ruby -Ilib:test "/usr/local/lib/ruby/gems/1.8/gems/rake-0.7.2/lib/rake/rake_test_loader.rb" "test/unit/book_test.rb" Loaded suite /usr/local/lib/ruby/gems/1.8/gems/rake-0.7.2/lib/rake/rake_test_loader Started E Finished in 0.01133 seconds. 1) Error: test_fixtures(BookTest): ActiveRecord::StatementInvalid: Mysql::Error: Table 'libris_test.books' doesn't exist: DELETE FROM books ...
Ugh. That doesn’t look pretty. After some googling around the following comes together
- Rename books.yml to libris_book.yml. The fixture yaml file has to share the same name as the database table name.
- Change the fixtures declaration to
- Use set_fixture_class to connect the fixture to the model class.
Here is our new and improved book_test.rb file:
require File.dirname(__FILE__) + '/../test_helper' class BookTest < Test::Unit::TestCase set_fixture_class :libris_book => Book fixtures :libris_book def test_fixtures assert_equal(2,Book.count) test_book = libris_book(:test_book) end end