Yes, I know, that testing private methods it's not a good idea (and I read this thread - http://www.ruby-forum.com/topic/197346 - and some others)
But how can I test the following code?
I use xmpp4r. In my public method #listen
I start receive jabber messages like so:
def listen @client.add_message_callback do |m| do_things_with_message(m) end end private def do_things_with_message(m) # end
#add_message_callback
- runs block, when message come (in different thread)
So, testing #listen
method it's difficult and it more testing xmpp4r than my #do_things_with_message
How to do all right and test #do_things_with_message
?:) (http://www.ruby-forum.com/topic/197346#859664)
Refactor private methods to a new object essentialy would be as I making them a public (and class with one method - it's senselessly
EDIT: This is more a theoretical question about clean code and the correct tests. In my first link people argue that the test private methods poorly. I don't want cheat with #send
, but also I don't see any viable ways to refactor
You shouldn't test private methods as they belong to the internal mechanism of the class. The purpose of Unit Tests is to check that your class behaves as expected when interacting with through its interface, i.e. its public methods.
In general, private methods can't be inherited in object-oriented programming languages. But in Ruby, private methods can also be inherited just like protected and public methods. The public method can be accessed outside the class in which they are defined.
Using BasicObject#instance_eval , you can call private method.
You can call a private method in ruby using the send
method. Something like this:
@my_object = MyObject.new @my_object.send(:do_things_with_message, some_message)
In a test that would look something like:
it "should do a thing" do my_object = MyObject.new my_object.send(:do_things_with_message, some_message) my_object.thing.should == true end
Putting aside the question of whether or not you should be testing a private method, it is very possible in Ruby to temporarily make a private method public. Here is what I mean:
# Metaprogrammatical magic to temporarily expose # a Class' privates (methods). 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
You would use publicize_methods
like this:
ClassToTest.publicize_methods do ... do_private_things_with_message(m).should ??? ... end
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With