That's right, Don't Repeat Yourself in your functional and ActionMailer tests. If you're a Test::Unit user, this will probably look familiar to you when writing Rails functional tests (for your controllers):

class PostsControllerTest < Test::Unit::TestCase
  def setup
    @controller = PostsController.new
    @request    = ActionController::TestRequest.new
    @response   = ActionController::TestResponse.new
  end

  def test_should_not_explode
    # Invariably sexy test code.
  end
end

You'd probably have noticed how setup always sets the @controller, @request and @response instance variables in all your controller tests. In Rails 2.0, you can instead subclass ActionController::TestCase (in turn a subclass of Test::Unit::TestCase) in your test cases and avoid repeating the instance variable assignments.

class PostsControllerTest < ActionController::TestCase
  # No need to define setup.

  def test_should_not_explode
    # Invariably sexy test code.
  end
end

Isn't that much better?

Watch out for a gotcha though, when you actually do need to define a setup method (like when you need to setup several other things before your tests run), as Jeffrey Allan Hardy reports. The issue has been resolved on edge Rails. If you're not using edge Rails, you should remember to always call super in your setup method should you define one:

class PostsControllerTest < ActionController::TestCase
  def setup
    super
    @user = users(:konata)
  end

  def test_should_not_explode
    # Invariably sexy test code.
  end
end

A similar subclass of Test::Unit, ActionMailer::TestCase is available for your ActionMailer unit tests as well. That means you can replace this:

class UserMailerTest < Test::Unit::TestCase
  include ActionMailer::Quoting

  def setup
    ActionMailer::Base.delivery_method = :test
    ActionMailer::Base.perform_deliveries = true
    ActionMailer::Base.deliveries = []

    @expected = TMail::Mail.new
    @expected.set_content_type "text", "plain", { "charset" => "utf-8" }
    @expected.mime_version = '1.0'
  end

  def test_signup
    # Test code.
  end
end

with this:

class UserMailerTest < ActionMailer::TestCase
  def test_signup
    # Test code.
  end
end

For the geeks among you, check out the related changeset.

About the contributor, Michael Koziarski

Michael Koziarski, better know as nzkoz, is a long-time Rails core committer. Michael has done a signficant amount of work improving the performance of ActiveRecord for Rails 2.0 so we have him to thank for a good portion of the optimization work done on ActiveRecord. He also keeps a fairly new personal blog.