This post originated from an RSS feed registered with Ruby Buzz
by Jay Fields.
Original Post: Rails: ActiveRecord Unit Testing part II
Feed Title: Jay Fields Thoughts
Feed URL: http://feeds.feedburner.com/jayfields/mjKQ
Feed Description: Blog about Ruby, Agile, Testing and other topics related to software development.
Back in December I wrote about unit testing ActiveRecord models. Following that post, we started using that pattern to unit test our models. It quickly became obvious that the ActiveRecord::ConnectionAdapters::Column.new("digits", nil, "string", false) statements were largely static and we wrapped this behavior in a fluent interface.
This worked, but some developers on the team didn't like the (arguably) unnecessary additional syntax. These developers argued that since none of our Unit Tests hit the database we should simply override the new method and handle stubbing the columns method.
You can argue that adding magic to the new method could be confusing, but our team has the standard that no unit test can hit the database. Therefore, everyone is very aware that, despite the standard syntax, we are injecting our own column handling mechanism.
The code to make this work is fairly straightforward. The usual alias method gotchas apply so I chose to use an alternative. Adding the following code will allow you to create disconnected models in your unit tests simply by calling new.
class << ActiveRecord::Base
new_method = instance_method :new define_method :new do |*attributes| attributes = attributes.empty? ? nil : attributes.first self.stubs(:columns).returns(no_db_columns(attributes)) new_method.bind(self).call attributes end
def no_db_columns attributes return [] if attributes.nil? attributes.keys.collect do |attribute| sql_type = case attributes[attribute].class when " " then "integer" when "Float" then "float" when "Time" then "time" when "Date" then "date" when "String" then "string" when "Object" then "boolean" end ActiveRecord::ConnectionAdapters::Column.new(attribute.to_s, nil, sql_type, false) end end