Evan Phoenix on Testing Private Methods in Ruby

Published on Friday, November 02, 2007 in ruby and testing

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
    def kill(num_victims)
      "#{num_victims} victims are no longer with us."

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)
    assert_equal '3 victims are no longer with us.', @ninja.flog_publicly(3)


$ ruby ninja.rb 
Loaded suite ninja
Finished in 0.000274 seconds.

1 tests, 1 assertions, 0 failures, 0 errors