Thanks to Jan Friedrich who pointed out the turn gem which displays what test is running, and when the test finishes, whether that test passed or failed. It’s an excellent tool that hasn’t received enough visibility.

See this comment for installation instructions.

Test::Unit doesn’t output the specifics of test failure and errors until the entire suite has completed running.

With a large enough (read: slow) suite, a lot of time can be wasted just waiting for tests to finish in order to figure out what’s actually broken.

Well, this is Ruby, so let’s just patch Test::Unit to do what we want. Add this to your test_helper.rb file, or put it somewhere handy. If there’s demand, I may package this up a bit better.

require 'test/unit/testresult'
class Test::Unit::TestResult
 
  alias :add_failure_original :add_failure
  def add_failure failure
    add_failure_original failure
    display_fault_now failure
  end
 
  alias :add_error_original :add_error
  def add_error error
    add_error_original error
    display_fault_now error
  end
 
  def display_fault_now fault
    puts ""
    puts fault.long_display
    puts ""
  end
 
end

A little-known and very useful feature Rails brings to the table in terms of testing is a pair of callback hooks for Test::Unit::TestCase setup and teardown.

The callback chains were introduced as part of the move toward a custom ActiveSupport::TestCase, but all the functionality of ActiveSupport::TestCase is exposed to Test::Unit::TestCase if you’re running Rails.

Having these hooks exposed allows you to inject setup and teardown behavior without stepping on the toes of any individual test.

class Test::Unit::TestCase
  def self.does_not_perform_validations klass
    setup do
      @preserved_validations = klass.validate.clone
      klass.validate.clear
    end
    teardown do
      @preserved_validations.each do |validation|
        klass.validate << validation
      end
    end
  end
end

Obviously this example is a little contrived, but perhaps you see how this can be used.

class MarshmallowTest < Test::Unit::TestCase
  does_not_perform_validations Marshmallow
  …
end

Now with a single macro, we can inject setup and teardown behavior for a model. The same technique can be used to inject teardown hooks from within individual tests, but beware, hooks injected in this way need to remove themselves from the callback chain when executing, or else they’ll be executed for every subsequent test teardown.

module Foo
  def shared
    'Foo shared'
  end
 
  def foobar
    shared
  end
end
 
module Moo
  def shared
    'Moo shared'
  end
 
  def moobar
    shared
  end
end
 
class Wingnut
  include Moo
  include Foo
end
 
w = Wingnut.new
 
w.foobar # => "Foo shared"
w.moobar # => "Foo shared"

In the old days, we did this:

User.find(:all, :conditions => { :subscribed => true }, :order => 'created_at DESC' )

And then this:

User.find_all_by_subscribed(true, :order => 'created_at DESC' )

How about this?

User.for_subscribed(true).order_by('created_at DESC').find(:all)

Here’s the how!

class User < ActiveRecord::Base
  named_scope_for :subscribed
end

Whup-cha!

class ActiveRecord::Base
  def self.named_scope_for attribute
    named_scope "for_#{attribute}",
      lambda { |attribute_value| { :conditions => { attribute => attribute_value } } }
  end
 
  named_scope :order_by, Proc.new { |*attributes|
    raise ArgumentError, 'You must specify an attribute to order by' if attributes.blank?
    { :order => attributes.join(', ') }
  }
end

Check it out it here, or install using git.

git clone git://github.com/duncanbeevers/named_scope_for.git vendor/plugins/named_scope_for

When dealing with ActionScript’s ExternalInterface.addCallback the method to be exposed might not be immediately available. whenAvailable polls until a property shows up on a javascript object, at which point it invokes the provided callback.

function whenAvailable(availableObject, availableProperty, onAvailable) {
  if ('object' != typeof(availabilityCheckers)) {
    availabilityCheckers = {};
  }
 
  var checkAvailabilityFunction = function(){
    if('undefined' != typeof(availableObject[availableProperty])){
      checker = availabilityCheckers[checkerInterval];
      clearInterval(checker.interval);
      checker.onAvailable(availableObject, availableProperty, availableObject[availableProperty]);
    }
  };
 
  var checkerInterval = setInterval(checkAvailabilityFunction, 500);
 
  availabilityCheckers[checkerInterval] = {
    interval: checkerInterval,
    onAvailable: onAvailable
  }
}