The solution highlighted by Jason (original implementation from Evan Phoenix) is nice from a maintainability perspective since it encapsulates changing the behavior of the class within the test. However, it's a bit verbose for my taste.
Reading the entry I couldn't help but think that gaining temporary access to a private method for testing seems like something that can be handled by a general solution instead.
Here's how I would have solved the problem.
private
" victims are no longer with us."
end
end
saved_private_instance_methods = self.private_instance_methods
self.class_eval {public *saved_private_instance_methods }
yield
self.class_eval {private *saved_private_instance_methods }
end
end
unit_tests do
test "kill returns a murder string" do
Ninja.publicize_methods do
assert_equal '3 victims are no longer with us.', Ninja.new.kill(3)
end
end
end
In this case, why not just use send()?
ReplyDeleteI believe the context of the conversation was how would you test in Ruby 1.9 since send will no longer allow you to call private methods.
ReplyDeleteHi Jay,
ReplyDeleteI was wondering, where would you put the publicize_methods class? Is it wise to have this in your normal code or should this be for testing only?
Also, your way is very slick and is less verbose. To me though, the other technique makes it a bit easier at a glance what it going on with the test. I will have to use both techniques to see which ends up winning.
Thanks!
DrMark,
ReplyDeleteLately I've been putting these type of methods in a *_extensions files (class_extensions for this example). You can put these files in an extension folder under the test directory.
Cheers, Jay
Any idea how to get rid of this warning?
ReplyDelete" `*' interpreted as argument prefix"
Just enclose the argument in parenthesis.
ReplyDeleteclass Class
def publicize_methods
saved_private_instance_methods = self.private_instance_methods
self.class_eval { public(*saved_private_instance_methods) }
yield
self.class_eval { private(*saved_private_instance_methods) }
end
end
Hi Jay,
ReplyDeleteI needed to test some private class methods so created a modified version for that purpose.