Opinionated Programmer - Jo Liss's musings on enlightened software development.

fail_fast for minitest (Test::Unit): Immediate backtrace & exit

Jan 2012: This is no longer working in my new Rails 3.2 app. I’m not sure why, or at what point it stopped working, but I’ll update this post when I find out. If anyone has a clue, please do let me know.

Feb 2012: Alan Johnson added a fail_fast option for tconsole, the fast MiniTest console. Check out minitest_handler.rb if you want the gory implementation details.


Original post preserved for posterity:

When I run the Test::Unit suite in my Ruby on Rails 3 project through “rake test” and a test is failing, the default behavior is to just print “F” or “E”, keep running until all the tests are finished (while I twiddle my thumbs), and only then print out a stack trace.

That’s very unhelpful for iterative development – I’d much prefer to get the stack trace immediately on failure or error, as with RSpec’s fail_fast option. Hence, I wrote the following monkey-patch for MiniTest::Unit (that’s minitest’s compatibility layer for Test::Unit tests), to be added in test/test_helper.rb if you’re using Rails:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# On failure/error, print stack trace and exit.
module MiniTest
  class Unit
    def puke_with_immediate_feedback(klass, meth, e)
      # Workaround for minitest weirdness: When puke gets called *again* after
      # @exiting has been set to true down below, exit immediately so we don't
      # get an extra SystemExit stack trace.  Exiting without exclamation mark
      # doesn't get the non-zero exit code through, but all teardown handlers
      # have been run at this point, so it's OK to use a hard exit here.
      exit! 1 if @exiting_from_puke
      result = puke_without_immediate_feedback(klass, meth, e)
      unless e.is_a?(MiniTest::Skip)
        # Failure or Error, so print the report we just wrote and exit.
        puts "\n#{@report.pop}\n"
        @exiting_from_puke = true
        exit 1
      end
      result
    end
    alias_method_chain :puke, :immediate_feedback
  end
end

If all you want is to have a stack trace printed immediately, you can of course remove all the exit lines, so the tests will keep running.