I recently spent not an insignificant amount of time trying to get my unit tests to comply with Rails’ single-table inheritance. Single table inheritance allows you to map a hierarchy of classes to a single table in the database, so from one user table I can have an Employee and a Manager. They both inherit from a User model in Rails, and are stored in the users database table. A manager, though, might have more properties (fields) and methods than an Employee, which can be defined in manager.rb:
class User < ActiveRecord::Base
class Manager < User
has_many :employees, :foreign_key => :user_id
def grant_payrise(employee, amount = 100)
employee.pay += amount
class Employee < User
belongs_to :manager, :foreign_key => :user_id
In the code above, both employees and managers are stored in the users table from which they inherit. However, Rails will recognise which users are managers and which are employees from clever use of a reserved string field on the users table called type. The type field stores which class of user a record represents, and Rails’ finders will automatically recognise that field. This means your controller can call:
[email protected] = Employee.find(:all)
That code will only return users who are employees, and return them as Employee objects.
My problem occurred when I tried to update my unit tests to cope with single-table inheritance. To keep things tidy, and separate my employee tests from my manager tests, I moved all my employee testing into test/units/employee_test.rb and my employee fixtures into test/units/employees.yml, and did the same for managers. When I ran the tests with a rake test:units, though, I was greeted with pages of SQL errors.
It turns out that you need to define all your fixtures to the root object (or direct descendent of ActiveRecord::Base), in my case the User class. So your tests for both employees and managers should still be placed in test/units/user_test.rb and the fixtures in test/units/fixtures.rb, e.g:
type: Manager # Note the type field must match the ActiveRecord
type: Employee # Note the type field must match the ActiveRecord class.
In hindsight, this makes sense, but after some thorough research (read: Google), I couldn’t find much - if anything - on unit testing single-table inheritance models, so thought I’d post a note to help anyone else in this situation.