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