Those who have used fixtures in Rails may know how handy they are when writing tests, helping us concentrate on the functionality, not having to worry about the test data. But, fixtures are not without their own problems.
- They do not go through validations. ActiveRecord validations are not run while creating fixtures and there is no guarantee that the fixtures form valid AR objects. I’ve found many invalid fixtures sitting in my projects, yet the tests running safely based on the inconsistent data. This might very well be the case with any rails project. What was the last time you ran .valid? on your fixture records?
- Records created through callbacks will have to be created manually. For instance, if there are UserObserver callbacks to create some records ‘on create’, they will have to be created manually. If not done, it’s a hole in the data set that is different from the one the real application uses in production/development. Hence, our tests might miss some data and cases that happen in production setup.
- Less motivation to create fixture records manually and hence decreased test coverage. Managing YML files manually is no fun. The harder a process, the lesser will be the motivation to follow it.
- Harder to maintain. It’s very hard to create records manually in some cases, like through tables. For instance, it took way too long for me to manually create all the intermediate table (in a habtm or has_many :through) records, which are supposed to be auto-generated by rails. Lets say, we have User has_many :cars, :through => :user_cars. Why should I create the user_car records by hand? Aren’t they supposed to be invisible to the application layer and hence the developer?
- Hard to get a complete picture of the test data from fixtures, especially when there are more join tables, STI, etc.,.
- Timestamps are absolute. The time values in the fixture data set are usually set to some hand-crafted time during the fixture creation. In some cases, the time may have to be closer to the time of test execution. Needless to say, it’s hard to update the time values for all the records in the fixtures when the need arises.
More than all these, fixtures do not appear to be the cleanest technique for the developers to create data at the data layer, wherein it’s real use lies in the application layer. We can very well write SQL statements for inserting fixtures, but it’s tedious and error prone. Fixtures are no different, except some support from Rails for naming records, associations, etc.,. But, they are still far from being an application layer functionality.
How about having a mechanism where we can write simple Rails code to create the fixture data? Fixture Generator plugin is just for that.
ruby script/plugin install firstname.lastname@example.org:venkatev/fixture_generator.git
class MyProjectFixtureGenerator < FixtureGenerator # Implement the 'populate' method in your populator. def populate # Create your records here and add them to the fixture set by calling # 'add_record(record_name, record_object)'. Please see lib/fixture_generator.rb for more details. end end
# Simply invoke the following line test environment to generate fixture YAML files. # MyProjectFixtureGenerator.generate # OR, even simple, run the following rake task. You may have to fix the fixture generator class name in the rake task # tasks/fixture_generator_tasks.rake # rake fixtures:generate
Modifying fixture data is now lot more easier. Just go to your fixture generator ruby file, modify the record creation statements, and run rake fixtures:generate. The new YML files are right there, ready to be used in your tests! Using this approach, we may not even need to revision control the fixtures. The generator script is the single source of fixture data. The developers can run the rake task and generate the fixtures locally. Give it a try and let me know your feedback.