At RubyConf today, Stuart Halloway’s Refactotum workshop led to a brief but excellent discussion on the various approaches for testing private methods in Ruby. Ideas ranged from the typical solution of using #send (which won’t work once Ruby 1.9 lands) to Ryan Davis’s technique of simply making everything public. Evan Phoenix, on the other hand, suggested a solution that avoids the soon-to-be-brokeness of using #send while still allowing you to benefit from the inherent intent expressed by defining a method as private .

To demonstrate, let’s assume we have the following (admittedly contrived) class:

class Ninja private def kill(num_victims) "#{num_victims} victims are no longer with us." end end

So how can we make sure that the private method is doing what we want, and do so while testing it in isolation? Why not temporarily define a new public method that simply passes through to our elusive private method?

require 'test/unit' class NinjaTest < Test::Unit::TestCase def test_should_punish_sloppy_coders @ninja = Ninja.new def @ninja.flog_publicly(*args) kill(*args) end assert_equal '3 victims are no longer with us.', @ninja.flog_publicly(3) end end

Sweet!

$ ruby ninja.rb Loaded suite ninja Started . Finished in 0.000274 seconds. 1 tests, 1 assertions, 0 failures, 0 errors