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.
require 'rubygems'
require 'dust'
require 'test/unit'
class Ninja
private
def kill(num_victims)
"#{num_victims} victims are no longer with us."
end
end
class 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
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
7 comments:
In this case, why not just use send()?
Reply DeleteI 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.
Reply DeleteHi Jay,
Reply DeleteI 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,
Reply DeleteLately 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?
Reply Delete" `*' interpreted as argument prefix"
Just enclose the argument in parenthesis.
Reply Deleteclass 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,
Reply DeleteI needed to test some private class methods so created a modified version for that purpose.
Note: Only a member of this blog may post a comment.
[フレーム]