Fed up with Rails fixtures? (part two)

Previously I described how you can write unit tests for ActiveRecord models without using fixtures – just using models in memory. Although only a limited subset of tests can be written this way, it’s often overlooked.

Another technique is to use constructor-based dependency injection (DI) in combination with mock objects. However, thanks to ActiveRecord::Associations::AssociationProxy#raise_on_type_mismatch it isn’t straightforward to use mocks for associated models. However, DI can be used effectively for ActionController controllers:

class ArticleController < ApplicationController
  def initialize(article_class = Article)
    super()
    @article_class = article_class
  end
  def show
    @article = @article_class.find(params[:id])
  end
end

The controller constructor defaults to using the real Article model class, but in the test we’re going to inject a mock object in its place. You could use one of the many mocking libraries for this, but I’m going to use our home-grown one, Mocha, in a “functional” controller test.

require File.dirname(__FILE__) + '/../test_helper'
require 'article_controller'

class ArticleController; def rescue_action(e) raise e end; end

class ArticleControllerTest < Test::Unit::TestCase
  def setup
    @article_class = mock()
    @controller = ArticleController.new(@article_class)
    @request    = ActionController::TestRequest.new
    @response   = ActionController::TestResponse.new
  end
  def test_should_display_article
    article = Article.new
    @article_class.expects(:find).with('1').returns(article)
    get :show, :id => 1
    assert_template 'show'
    assert_equal article, assigns(:article)
  end
end

I wrote this at about 6am on the train from Durham to London without the aid of a coffee, so it may not make much sense!