Setting Up a Test Database with Fixtures

Automated testing needs a stable database environment in which to do its work. The contents of the development database will—and should—change on a regular basis as you tinker, try things out, and experiment to see just how well everything works. This is wonderful for a human development process, but that level of change is dreadful when a computer is testing an application. Once the testing framework is told which value to check for, it can’t choose another value because it knows someone else was playing with the data. In fact, if previous tests change the data, the order in which tests are conducted could itself become an issue, masking some bugs and falsely reporting others.

Rails provides this stable environment two ways. First, as noted earlier, it maintains a separate test environment, complete with its own database. Second, the testing environment expects that developers will define stable data, called fixtures, for use in that database. Every time a new test is run, the database is reset to that stable set of data. It’s a slow way to do things, but it’s extremely reliable.

Fixtures are written in YAML. You don’t need to know much about YAML to use and create them, however. Rails, in fact, has been creating fixtures along with scaffolding all along. If you check the test/fixtures directory of the courses and students application, you’ll see files named awards.yml, courses.yml, and students.yml. Their contents aren’t particularly exciting, though, as Example 12-1 demonstrates.

Example 12-1. The students.yml fixture file created by Rails

# Read about fixtures at http://ar.rubyonrails.org/classes/Fixtures.html

one:
  given_name: MyString
  middle_name: MyString
  family_name: MyString
  age: 1
  grade_point_average: 9.99
  start_date: 2008-06-27

two:
  given_name: MyString
  middle_name: MyString
  family_name: MyString
  age: 1
  grade_point_average: 9.99
  start_date: 2008-06-27

Each field has a value, set by the Rails generator to reflect its type, and there are two records, but you may want something more reflective of the data your application is likely to contain, like Example 12-2.

Example 12-2. A more realistic, though still brief, students.yml fixture

giles:
  given_name: Giles
  middle_name: Prentiss
  family_name: Boschwick
  date_of_birth: 1989-02-15
  grade_point_average: 3.92
  start_date: 2006-09-12

milletta:
  given_name: Milletta
  middle_name: Zorgos
  family_name: Stim
  date_of_birth: 1989-04-17
  grade_point_average: 3.94
  start_date: 2006-09-12

jules:
  given_name: Jules
  middle_name: Bloss
  family_name: Miller
  date_of_birth: 1988-11-12
  grade_point_average: 2.76
  start_date: 2006-09-12

It’s up to you whether you’d like the data to echo the development database, but somewhat meaningful data can be useful when you’re trying to find your way through results, especially failures.

Warning

If you try to run tests based on the generated fixtures and your migrations set constraints on which fields can be null, you’ll get a lot of mysterious errors. In SQLite, they suggest that your database and all of its tables are missing—even though they’re not. When using MySQL, the error message at least narrows things down to fields, but that still doesn’t explain why there’s a problem.

The scaffold fixtures may work for testing incredibly simple applications, but most of the time you’ll be much better off defining your own fixtures carefully.

There’s more you can do in upgrading fixtures than improving readability, however. The fixtures Rails created don’t know very much about relationships between models because the fixtures were generated before you told Rails about the relationship. So, for example, the generated fixture for awards looks like Example 12-3.

Example 12-3. The generated awards.yml fixture, without much real data

one:
  name: MyString
  year: 1
  student_id: 1

two:
  name: MyString
  year: 1
  student_id: 1

Rails knows that student_id is a number and gives it a value of 1, which should connect to a student, although as you might have noticed in Example 12-1, the students.yml fixture didn’t include id values. The database might start its id count at 1, or it might not.

Note

Fixture data isn’t validated before it’s loaded into the database. While this might conceivably offer more testing flexibility, you should never assume that fixture data will validate against the model until you’ve made certain that it does.

Example 12-4 shows a better way to create this fixture, taking advantage of the names in the student.yml file that was shown in Example 12-2.

Example 12-4. The awards.yml fixture, populated with semi-real data and links to students

# instead of computing student_id for each award and giving students
# explicit id fields, we reference the student by the name of their
# fixture

skydiving:
  name: Sky Diving Prowess
  year: 2007
  student: giles

frogman:
  name: Frogman Award for Underwater Poise
  year: 2008
  student: jules

It’s important to note that the names of students used to make the connections aren’t coming from the given_name field. They’re the names that were assigned to each student object in the fixture. The same thing applies to the fixture, only it can actually refer to multiple students, not just one. The original fixture, shown in Example 12-5, doesn’t even specify any students for courses. Example 12-6, by contrast, establishes relationships, using the names of the fixtures.

Example 12-5. The generated courses.yml fixture, with very little content

one:
  name: MyString

two:
  name: MyString

Example 12-6. The courses.yml fixture, populated with sort of real data

# instead of making us write elaborate and fragile data structures,
# the fixtures engine knows how to turn the 'students' list into a
# collection of records to insert into the courses_students table.

opera:
  name: Mathematical Opera
  students: giles, milletta

# it's safest to quote strings, especially if they contain colons
reptiles:
  name: "Reptiles: Friend or Foe?"
  students: giles, jules

immoral:
  name: "Immoral Aesthetics"
  students: milletta

The fixtures setup is smart enough to establish the many-to-many connection between courses and students and build the necessary table, when given data like Example 12-6.

Note

You can edit these files by hand, or you can generate fixtures from the development database with the ar_fixtures plug-in. You can find out more about ar_fixtures at http://railsify.com/plugins/8-ar_fixtures. You can even create dynamic fixtures if you want, though that’s well beyond the scope of this book.

Once you have your fixtures set up, you can try running rake test. You’ll probably get a lot of errors, because the tests themselves aren’t well set up. A lot of errors is a normal place to start in testing, however—it just means there’s a lot to fix!

When you run rake test, Rails will clone the structure (but not the content) of your development database into the test database. It doesn’t run the migrations against the test database directly, but it does check to make sure your database is up-to-date with its migrations. If it isn’t, you’ll get a warning like:

You have 4 pending migrations:
  20080627135838 CreateStudents
  20080627140324 CreateCourses
  20080627144242 CreateCoursesStudents
  20080627150307 CreateAwards
Run "rake db:migrate" to update your database then try again.

If you get major error messages that sound like your database can’t be found, as noted in the warning earlier, check your fixtures to ensure that every field your migrations said had to be there has an actual value.

Once you have the fixtures set up, it’s time to move on to the tests.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset