MetaSkills.net
Coding things under other things!

Using MiniTest::Spec With Rails

So after a few blog post on the subject of MiniTest::Spec, I finally have a simple testing stack for Rails 3 that leverages MiniTest's spec DSL. I introduce to you the MiniSpecUnit gem. MiniSpecUnit defines a Test::Unit::TestCase class that subclasses MiniTest::Spec. It implements only what is needed to make rails happy. It is not a drop in replacement for the real Test::Unit::TestCase that is included with ruby 1.9.

Once you bundle the gem in your Rails application, it will satisfy the require "test/unit/testcase" from ActiveSupport's test case. Tricking it to use MiniTest::Spec instead of MiniTest::Unit. Here is an example Gemfile that shows the usage of MiniSpecUnit as well as two other MiniTest gems that I have made. The first is MiniBacktrace which allows you to leverage the Rails.backtrace_cleaner using MiniTest. The other is MiniShoulda which builds a simple Shoulda syntax on top of MiniTest::Spec.

group :test do
  gem 'minitest'          # At least v2.0.2 if using MiniShoulda.
  gem 'mini_specunit'     # The goods! Force MiniTest::Spec instead of MiniTest::Unit.
  gem 'mini_backtrace'    # Use Rails.backtrace_cleaner with MiniTest.
  gem 'mini_shoulda'      # A small Shoulda syntax on top of MiniTest::Spec.
end

Since MinitTest::Spec is built on top of MiniTest::Unit, there is not a lot that can go wrong. With MiniSpecUnit, we finally have a working solution by replacing MiniTest::Spec as the superclass for ActiveSupport::TestCase when using Rails. This solution is drop dead simple and does not require you to recreate a new test case in your test_helper.rb and change all your cases to subclass that new test case. About the only gotcha is a few missing assertions available in Test::Unit. If you encounter these, I encourage you to rewrite them to the modern MiniTest::Spec assertion style. I commonly use this cheat sheet to remember them. For example:

# This:
assert_not_nil @foo.bar

# Would Become This:
@foo.bar.wont_be_nil

Functional Tests With ActionController::TestCase

One problem you may have with your functional tests is a nil @controller instance variable in describe or context blocks. Resulting in the "RuntimeError: @controller is nil: make sure you set it in your test's setup method." message. This is easy to fix, all you have to do is be explicit about your controller that you are testing like so.

class UsersControllerTest < ActionController::TestCase
  tests UsersController
  ...
end

Broken Describe Scopes

In my article, From Test::Unit & Shoulda To MiniTest::Spec & MiniShoulda, I cover a patch to MiniTest that would fix "undefined local variable or method" errors when using describe/context scopes. I submitted a patch and pull request to Ryan Davis that I believe was applied. At the time of this article, there is no release version of MiniTest that includes this patch that I have in MiniShoulda. So if you find yourself with errors in describe/context blocks, consider bundling the MiniSholda gem to fix it till a new version of MiniTest is released.

In Closing

I have only tested the above stack in the latest Rails edge, 3.1.beta and ruby 1.9.2. I doubt there are issues on older versions of Rails with different Ruby versions. If you apply these gems to success, I would love to hear about it. Happy testing!