Evan Phoenix on testing private methods in Ruby
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