I just wrote a simple unit test which indirectly resulted in calling create for the AR object. The problem is that I don’t want to create objects in my unit tests – in particular, I try to avoid hitting the database (or disk, or network for that matter) as much as possible, keeping my unit tests fast. Sure, actual calls to create, save etc. need to be tested too, but I’ll leave those for the integration tests.

So, I wanted to make a simple reminder which nags to me whenever I call create for AR objects indirectly or directly, but I only want those alerts when running stuff inside test/unit directory. I modified ActiveRecord::Base#create slightly to warn the user about using it, and placed it in the test/unit directory by naming it so that it is loaded first (aardvardks_automatic_insinuation_for_spline_reticulation_test.rb would work just fine):

1
2
3
4
5
6
7
8
9
10
11
12
13


class ActiveRecord::Base
  @@_nagged_already = false
  alias_method :orig_create, :create
  def create(*args)
    if not @@_nagged_already
      warn "\nPlease avoid calling ActiveRecord#create in unit tests (mock/stub stuff instead)"
      @@_nagged_already = true
    end
    orig_create(*args)
  end
end

Now, running rake test:units warns about use of create, but it doesn’t affect any other tests (like test:functionals or test:integration).

Alright, it’s a bit of a hack, but Works For Me™.

1 Response to “Mock/Stub police for your Ruby/Rails unit tests”

  1. EdvardM Says:

    You might want to see where the code was called from. More nagging version showing the call lines is attached below:

    WARNING_TEMPLATE = "\n*** %s\n*** Please avoid calling ActiveRecord#create in unit tests (mock/stub stuff instead)" 
    class ActiveRecord::Base
    
      alias_method :orig_create, :create
      def create(*args)
        warn(WARNING_TEMPLATE % caller(0).select { |l| l =~ /test\/unit/ }.join("\n"))
        orig_create(*args)
      end
    end
    

Sorry, comments are closed for this article.