Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do you stub ActiveRecord::Base methods without making assumptions about how it's used?

ActiveRecord::Base has a big ol' API with multiple methods for both finding and saving objects. For example, your AR::B objects might have been instantiated from a number of methods:

  • Foo.new(…)
  • Foo.create(…)
  • Foo.find(…)
  • Foo.find_by_sql(…)
  • Foo.find_[all_]by_*(…)
  • bar.foos (associations)
    • …and finder methods on associations, of course

Similarly, the object in question might get persisted by a few different methods:

  • foo.create or foo.create!
  • foo.save or foo.save!
  • foo.update_attributes or foo.update_attributes!

Now, when writing unit tests, it's good practice to stub external method calls so that your test can focus on the business logic of the method in question. However, when it comes to working with AR::B objects – for example in controller unit tests – it seems like you have to commit to one of the above methods, when actually as far as the business logic of the method is concerned it shouldn't be important which you choose.

Do you have to couple the behaviour of your method this tightly with its implementation or am I missing something simple?

like image 327
Gareth Avatar asked Mar 15 '12 11:03

Gareth


1 Answers

One approach is to build your classes in such a way that you wrap up any ActiveRecord::Base method calls in your own methods.

So instead of calling Foo.new(…) directly...

class Foo < ActiveRecord::Base
  def self.create_object(…)
    new(…)
  end
end

That way in your tests you can stub out your own methods instead of ActiveRecord's.

This approach (including its' benefits) is outlined in detail by Avdi Grimm in the book 'Objects On Rails'... http://objectsonrails.com

like image 87
Paul Sturgess Avatar answered Oct 31 '22 07:10

Paul Sturgess