Loading Test Data with YAML Fixtures

Problem

It's important that your test database contains known data that is common to each test case for the model being tested. You don't want your tests to pass or fail depending on what's in the database when they run; that defeats the whole purpose of testing. You have created data to test the boundary conditions of your application, and you want an efficient way to load that data into your database without using SQL.

Solution

Use YAML to create a file containing test fixtures to be loaded into your test database.

Your database contains a single books table as created by the following migration:

db/migrate/001_build_db.rb:

class BuildDb < ActiveRecord::Migration
 def self.up
 create_table :books do |t|
 t.column :title, :string
 t.column :CNPJ, :string
 t.column :ean, :string
 t.column :upc, :string
 t.column :edition, :string
 end
 end
 def self.down
 drop_table :books
 end end

Create a Book model using the Rails generate script (notice the test scaffolding that's created by this command):

$ ruby script/generate model book
 exists app/models/
 exists test/unit/
 exists test/fixtures/
 create app/models/book.rb
 create test/unit/book_test.rb
 create test/fixtures/books.yml

Now, create a fixture containing your test data in the books.yml file under the test/fixtures directory:

test/fixtures/books.yml:

perl_cookbook:
 id: 1 
 title: Perl Cookbook
 CNPJ: 957824732X
 ean: 9789578247321
 upc: 636920527114
 edition: 1
java_cookbook:
 id: 2 
 title: Java Cookbook
 CNPJ: 9867794141
 ean: 9789867794147
 upc: 236920522114
 edition: 1
mysql_cookbook:
 id: 3 
 title: MySQL Cookbook
 CNPJ: 059652708X
 ean: 9780596527082
 upc: 636920527084
 edition: 2

Fixtures are loaded by the Test::Unit module by passing the name of the fixture file, without the extension, as a symbol to the fixtures method. The following unit test class shows the books fixtures being loaded with a test confirming success:

test/unit/book_test.rb:

require File.dirname(__FILE__) + '/../test_helper'
class BookTest < Test::Unit::TestCase
 fixtures :books
 def test_fixtures_loaded
 perl_book = books(:perl_cookbook)
 assert_kind_of Book, perl_book
 end end

Discussion

YAML is a data serialization format designed to be easily readable and writable by humans, as well as by scripting languages such as Python and Ruby. YAML is often used for data serialization and configuration settings, where it serves as a more transparent alternative to XML or a custom configuration language.

Before it runs each test case, the Test::Unit module uses the solution's fixture file (books.yml) to initialize the books table of the test database. In other words, each test case starts with a fresh copy of the test data, just as it appears in the YAML fixture. This way, tests can be isolated with no danger of side effects.

The test_fixtures_loaded test case of the BookTest class tests that the book fixtures are loaded successfully and that an Active Record Book object is created. Individual records in a YAML fixture are labeled for convenient reference. You can use the books fixture accessor method to return book objects by passing it one of the fixture labels. In the solution, we return an object representing the Perl Cookbook by calling books(:perl_cookbook). The assertion tests that this object is, in fact, an instance of the Book class. The following output shows the successful results of running the test:

$ ruby ./test/unit/book_test.rb 
Loaded suite test/unit/book_test Started
.
Finished in 0.05485 seconds.
1 tests, 1 assertions, 0 failures, 0 errors

See Also