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!