unit-testing junit mockito - How do I test a private function or a class that has private methods, fields or inner classes?
The best way to test a private method is via another public method. If this cannot be done, then one of the following conditions is true:
- The private method is dead code
- There is a design smell near the class that you are testing
- The method that you are trying to test should not be private
How do I unit test (using xUnit) a class that has internal private methods, fields or nested classes? Or a function that is made private by having internal linkage (
static in C/C++) or is in a private (anonymous) namespace?
It seems bad to change the access modifier for a method or function just to be able to run a test.
I have used reflection to do this for Java in the past, and in my opinion it was a big mistake.
Strictly speaking, you should not be writing unit tests that directly test private methods. What you should be testing is the public contract that the class has with other objects; you should never directly test an object's internals. If another developer wants to make a small internal change to the class, which doesn't affect the classes public contract, he/she then has to modify your reflection based test to ensure that it works. If you do this repeatedly throughout a project, unit tests then stop being a useful measurement of code health, and start to become a hindrance to development, and an annoyance to the development team.
What I recommend doing instead is using a code coverage tool such as Cobertura, to ensure that the unit tests you write provide decent coverage of the code in private methods. That way, you indirectly test what the private methods are doing, and maintain a higher level of agility.
Generally a unit test is intended to exercise the public interface of a class or unit. Therefore, private methods are implementation detail that you would not expect to test explicitly.
The private methods are called by a public method, so the inputs to your public methods should also test private methods that are called by those public methods. When a public method fails, then that could be a failure in the private method.
To test legacy code with large and quirky classes, it is often very helpful to be able to test the one private (or public) method I'm writing right now.
I use the junitx.util.PrivateAccessor-package for Java . Lots of helpful one-liners for accessing private methods and private fields.
import junitx.util.PrivateAccessor; PrivateAccessor.setField(myObjectReference, "myCrucialButHardToReachPrivateField", myNewValue); PrivateAccessor.invoke(myObjectReference, "privateMethodName", java.lang.Class parameterTypes, java.lang.Object args);
As others have said... don't test private methods directly. Here are a few thoughts:
- Keep all methods small and focused (easy to test, easy to find what is wrong)
- Use code coverage tools. I like Cobertura (oh happy day, looks like a new version is out!)
Run the code coverage on the unit tests. If you see that methods are not fully tested add to the tests to get the coverage up. Aim for 100% code coverage, but realize that you probably won't get it.
If using Spring, ReflectionTestUtils provides some handy tools that help out here with minimal effort. For example, to set up a mock on a private member without being forced to add an undesirable public setter:
ReflectionTestUtils.setField(theClass, "theUnsettableField", theMockObject);
In the Spring Framework you can test private methods using this method:
ReflectionTestUtils.invokeMethod(TestClazz, "createTest", "input data");
If you want to test private methods of a legacy application where you can't change the code, one option for Java is jMockit, which will allow you to create mocks to an object even when they're private to the class.
I tend not to test private methods. There lies madness. Personally, I believe you should only test your publicly exposed interfaces (and that includes protected and internal methods).
A private method is only to be accessed within the same class. So there is no way to test a “private” method of a target class from any test class. A way out is that you can perform unit testing manually or can change your method from “private” to “protected”.
And then a protected method can only be accessed within the same package where the class is defined. So, testing a protected method of a target class means we need to define your test class in the same package as the target class.
If all the above does not suits your requirement, use the reflection way to access the private method.
As many above have suggested, a good way is to test them via your public interfaces.
If you do this, it's a good idea to use a code coverage tool (like Emma) to see if your private methods are in fact being executed from your tests.
Please see below for an example;
The following import statement should be added:
Now you can directly pass the object which has the private method, method name to be called, and additional parameters as below.
Whitebox.invokeMethod(obj, "privateMethod", "param1");
First, I'll throw this question out: Why do your private members need isolated testing? Are they that complex, providing such complicated behaviors as to require testing apart from the public surface? It's unit testing, not 'line-of-code' testing. Don't sweat the small stuff.
If they are that big, big enough that these private members are each a 'unit' large in complexity -- consider refactoring such private members out of this class.
If refactoring is inappropriate or infeasible, can you use the strategy pattern to replace access to these private member functions / member classes when under unit test? Under unit test, the strategy would provide added validation, but in release builds it would be simple passthrough.
For Java I'd use reflection, since I don't like the idea of changing the access to a package on the declared method just for the sake of testing. However, I usually just test the public methods which should also ensure the private methods are working correctly.
you can't use reflection to get private methods from outside the owner class, the private modifier affects reflection also
This is not true. You most certainly can, as mentioned in Cem Catikkas's answer.