What\'s the best way to unit test protected and private methods in Ruby, using the standard Ruby Test::Unit
framework?
I\'m sure somebody will pipe up a
In order to do this:
disrespect_privacy @object do |p|
assert p.private_method
end
You can implement this in your test_helper file:
class ActiveSupport::TestCase
def disrespect_privacy(object_or_class, &block) # access private methods in a block
raise ArgumentError, 'Block must be specified' unless block_given?
yield Disrespect.new(object_or_class)
end
class Disrespect
def initialize(object_or_class)
@object = object_or_class
end
def method_missing(method, *args)
@object.send(method, *args)
end
end
end
You can bypass encapsulation with the send method:
myobject.send(:method_name, args)
This is a 'feature' of Ruby. :)
There was internal debate during Ruby 1.9 development which considered having send
respect privacy and send!
ignore it, but in the end nothing changed in Ruby 1.9. Ignore the comments below discussing send!
and breaking things.
To correct the top answer above: in Ruby 1.9.1, it's Object#send that sends all the messages, and Object#public_send that respects privacy.
I would probably lean toward using instance_eval(). Before I knew about instance_eval(), however, I would create a derived class in my unit test file. I would then set the private method(s) to be public.
In the example below, the build_year_range method is private in the PublicationSearch::ISIQuery class. Deriving a new class just for testing purposes allows me to set a method(s) to be public and, therefore, directly testable. Likewise, the derived class exposes an instance variable called 'result' that was previously not exposed.
# A derived class useful for testing.
class MockISIQuery < PublicationSearch::ISIQuery
attr_accessor :result
public :build_year_range
end
In my unit test I have a test case which instantiates the MockISIQuery class and directly tests the build_year_range() method.