How to test private functions in a module
I have a two part question:
Part 1
I have a module that has a public class method which depends on a few private helper methods in the module. What is the best way to test these private helper methods? They contain complex logic that needs to be tested, but they should not be exposed to be called as they alone provide nothing useful.
I read on this stackoverflow post that the convention is to do:
modu开发者_高级运维le GTranslate
class Translator
def perform( text ); 'hola munda'; end
end
def self.translate( text )
t = Translator.new
t.perform( text )
end
end
and then write tests on the public methods of class GTranslate::Translator
. However, I do not want this class to be able to instantiate or have the methods on them called.
Part 2
Seeing that the public method on a module is defined as self.someMethodName
, does this mean the helper methods have to be defined as self.helperName
?
There will be no instance of a module (if you can even create instances of modules (I'm new to Ruby)) so I can't use the send
method defined on an instance to invoke the method from my tests?
Any ideas?
There is some bit of debate about testing private methods as you will see in other answers. Before you test them you should consider whether it is the best choice. David Brady has a great podcall with Robert C. (Uncle Bob) Martin where they discuss this issue and some of the possible solutions including testing through the public interface, and refactoring into a separate class.
That being said, this is Ruby. If you want to test private methods use instance_eval
(or class_eval
for class methods) to run your test in the context of the module.
edit: After some quick IRB work modules take a little more work
Given:
module Foo
class << self
private
def bar
...
end
end
end
To test Foo.bar put in your test file:
Module Foo
class << self
puiblic :bar
end
end
For the duration of your tests bar
will be public and visible.
end edit
See also:
- Yes You Should Test Private Methods (Sometimes)
- Test Everything, But Not Private Methods
- MORE Testing Private Method
I would say you have three options.
Find a way to test the functionality using the class's public methods. All the class functionality should generally be exposed by its public methods. If you can't test a class just by using its public methods, this may indicate a deeper problem with the design.
If option 1 doesn't work (and indeed sometimes it doesn't), refactor the private functionality out to a separate class, in which these methods are public. This seems to be what you're suggesting, and I don't see a problem with that. Testing is an integral part of the system you're building and should be treated as such. Making functionality public "just for testing" is completely valid in my opinion.
Make the functions public and test them. This is technically easiest but is less clean than option 2.
There are two cases:
- The private method gets called by a public method, or by a private method that gets called by a public method, or by a private method that gets called by a private method that gets called by a public method, or … (you get the idea). In that case, you don't need to test the private method, because it is already tested through the public method.
- The private method never gets called by a public method. In that case, you don't need to test it either, you can simply delete it because it never gets called.
So, in both cases you simply don't need to test it in the first place.
(Note that it's a little bit more complicated than that, since the private method might be called via reflection or other means. But the gist is: either someone somewhere calls the private method, in which case it is tested through that someone, or noone calls the private method, in which case it is dead code.)
If I may make a small advertisement for Test-Driven Development: in TDD, it is actually impossible for untested private methods to exist. The only way for a private method to be introduced into the system, is by extraction from an already tested public method. (Actually, in TDD, it is impossible for any untested code to exist, so the statement that it is impossible for untested private methods to exist is trivially true.)
In general, private methods usually are created by extracting them from a public method that has become too big or too complex. The nice thing about this is that the Extract Method Refactoring has a very convenient property: like all other Refactorings, it doesn't change the externally observable behavior, but unlike many other Refactorings, which entail rather significant changes to the internal logic (e.g. the Null Object Refactoring or the Replace Conditional With Polymorphism Refactoring), it does not change the internal logic, either. It just shuffles code around. (In fact, with a good optimizing compiler like the one in Rubinius, IronRuby or JRuby, the calls to the private methods will probably be inlined, so that the code that gets actually executed is 100% the same both before and after extracting the methods.)
So, if your code was tested before you moved into a private method, then it is guaranteed to still be tested after you move it.
精彩评论