Rails Testing Fixtures Extended

Posted by scientific on October 11, 2006

I have some meta-data stored in tables that I wanted to check with a unit test in Rails. I want to be sure that all the data are loaded correctly, every time. I have built some migration code that allows me to load YAML files directly into a SQL database (bypassing activerecord, unfortunately, because AR won’t let us specify which id is associated with which record: a critical necessity for lookup tables).

So I built a test helper that loads data from a YAML file and compares it with all the data in an ActiveRecord model to be sure that the two datasets are identical.
It’s a pretty simple implementation once we get a few details figured out. First we want to process the YAML file for any embedded Ruby (ERB) code, just like Rails’ Test::Unit does:

YAML::load(ERB.new(IO.read(ymlfile_with_path)).result)

Then we simply loop through the records represented by the loaded YAML data and compare them with the data in the ActiveRecord model. We do this by using “find” in the AR model using the YAML record’s id value:

 activerecord_class.find(recordvalue[ID_FIELDNAME])

Finally, and coolest, we loop through the every element in the YAML file and look for an associated column/value pair in ActiveRecord. We use a neat trick to get ActiveRecord to look up our key from YAML. We “send” the name of the key as a symbol as a method message to AR. AR will catch this name and look to see if there is a column in the table that matches. So, these two lines would be equivalent (though one is dynamic and one is static):

key = "title"
activerecord_instance.send(key.to_sym)
#is the same as this, except we are using a variable above, pulled from a YAML file (or wherever else)
activerecord_instance.send(:title)

To use the complete test helper method yourself, add this code below to your “class Test::Unit::TestCase” in test/testhelp.rb

  #uses yml file to find all records in activerecord_class
  #assumes that yml file contains ALL rows in activerecord_class and vice versa
  def compare_yml_to_table(ymlfile_with_path, activerecord_class)
    #load file into YAML, first processing with ERB to expand any Ruby code in YAML file
    records = YAML::load(ERB.new(IO.read(ymlfile_with_path)).result)
    #loop through yaml file records
    records.each do |recordname, recordvalue|
      #find associated id in DataPriority model
      activerecord_instance = activerecord_class.find(recordvalue[ID_FIELDNAME])
      #loop through data elements for this record
      #sending the key to activerecord_instance object instance as a symbol, to invoke associated method
      #Example: if key = "code" this is equiv to statically calling datapriority.code
      recordvalue.each do |key, value|
        tableval = activerecord_instance.send(key.to_sym)
        #compare row values across activerecord and YML file
        assert_equal value, tableval
      end #recordvalue.each
    end #records.each
    #compare overall table sizes between activerecord and YML file
    assert_equal records.size, activerecord_class.count
    #ensure that we aren't dealing with 0 records on both sides
    assert records.size>0
  end # def compare_yml_to_table
Trackbacks

Use this link to trackback from your own site.

Comments

Leave a response

Comments