0

I have a class that contains a bunch of methods, I have written unit tests for each method. The main method in the class is the encrypt method, which takes a message and encrypts it. I have also written like 5 other methods that are used by this encrypt method, but I don't want the user to be able to call these methods, I just want to use them inside the encrypt method to get the job done, but I don't want the user to do like @obj.some_method_that_is_not_encrypt, I want to make only the encrypt method invokable, I know I can make these methods private, but then my unit tests will fail. How do I go about dealing with this ?

Ahmad Al-kheat
  • 1,805
  • 2
  • 16
  • 25
  • 1
    see here http://stackoverflow.com/questions/267237/whats-the-best-way-to-unit-test-protected-private-methods-in-ruby you can use send to get around the private. – Doon Apr 13 '15 at 16:56
  • @Doon but isn't this smelly? – Ahmad Al-kheat Apr 13 '15 at 16:58
  • 2
    Smell determination is left as an exercise for the reader :) it opens up a whole new can of worms. But the fact that your (or your classes) users can do this and bypass private means private should be treated as a suggestion anyways. But alas I don't have a good answer for it.. I normally test the public interfaces / behavior of the class as opposed to each function, for right or wrong. – Doon Apr 13 '15 at 17:03

1 Answers1

1

Your unit tests can use Object#send(...) to invoke private methods:

class Foo
private
  def bar
    "ok"
  end
end

f = Foo.new
f.bar # => NoMethodError: private method `bar' called...
f.send(:bar) # => "ok"

So your "encrypt" method could be the only public one but it can still use private methods which are not exposed to polite users of your library (they can, of course, use send also if they want).

Note also that a peculiar aspect of "private" methods is that they cannot be invoked with an explicit receiver, even in the same class. So you could not call self.my_private_method, instead you must simply call my_private_method. For example:

class Foo
  def foo
    self.bar # => NoMethodError: private method `bar' called...
    bar # => "ok"
  end
private
  def bar; "ok"; end
end
maerics
  • 151,642
  • 46
  • 269
  • 291