Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Testing private method in Ruby (rspec) [duplicate]

Tags:

ruby

rspec

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

like image 553
Andrey Avatar asked May 16 '13 23:05

Andrey


People also ask

Should you test private methods Ruby?

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.

Are private methods inherited Ruby?

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.

How do you call a private method in Ruby?

Using BasicObject#instance_eval , you can call private method.


Video Answer


2 Answers

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 
like image 124
Andrew Hubbs Avatar answered Oct 14 '22 20:10

Andrew Hubbs


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 
like image 20
buruzaemon Avatar answered Oct 14 '22 20:10

buruzaemon