Take the 2-minute tour ×
Programmers Stack Exchange is a question and answer site for professional programmers interested in conceptual questions about software development. It's 100% free, no registration required.

I am working on a java project. I am new to unit testing. What is the best way to unit test private methods in java classes?

share|improve this question
1  
Check this question on StackOverflow. A couple of techniques are mentioned and discussed. What's the best way of unit testing private methods? –  Chiron Aug 14 '11 at 5:02
18  
My opinion has always been that private methods don't need testing as you should be testing what is available. A public method. If you can't break the public method does it really matter what the private methods are doing? –  Rig Apr 12 '12 at 18:22

10 Answers 10

up vote 123 down vote accepted

You generally don't unit test private methods directly. Since they are private, consider them an implementation detail. Nobody is ever going to call one of them and expect it to work a particular way.

You should instead test your public interface. If the methods that call your private methods are working as you expect, you then assume by extension that your private methods are working correctly.

share|improve this answer
23  
+1 bazillion. And if a private method is never called, don't unit-test it, delete it! –  Steven A. Lowe Aug 14 '11 at 6:08
101  
I disagree. Sometimes a private method is just an implementation detail, but it still is complex enough that it warrants testing, to make sure it works right. The public interface may be offering a too high level of abstraction to write a test which directly targets this particular algorithm. It's not always feasible to factor it out into a separate class, for due to the shared data. In this case I'd say it's OK to test a private method. –  quant_dev Aug 14 '11 at 8:04
4  
@Hippo: if your class has a private method that is never called, it is dead code and you do not need it. – –  Steven A. Lowe Aug 14 '11 at 10:56
6  
Of course delete it. The only possible reason not to delete a function you aren't using is if you think you may need it in the future, and even then you should delete it but note the function in your commit logs, or at least comment it out so that people know it's extra stuff they can ignore. –  jhocking Aug 14 '11 at 11:44
21  
@quant_dev: Sometimes a class needs to be refactored into several other classes. Your shared data can be pulled into a separate class too. Say, a "context" class. Then your two new classes can refer to the context class for their shared data. This may seem unreasonable, but if your private methods are complex enough to need individual testing, it's a code smell that indicates your object graph needs to become a little more granular. –  Phil Jul 17 '12 at 14:47

In general, I would avoid it. If your private method is so complex that it needs a separate unit test, it often means that it deserved its own class. This may encourage you to write it in a way which is reusable. You should then test the new class and call the public interface of it in your old class.

On the other hand, sometimes factoring out the implementation details into separate classes leads to classes with complex interfaces, lots of data passing between the old and new class, or to a design which may look good from the OOP point of view, but does not match the intuitions coming from the problem domain (e.g. splitting a pricing model into two pieces just to avoid testing private methods is not very intuitive and may lead to problems later on when maintaining/extending the code). You don't want to have "twin classes" which are always changed together.

When faced with a choice between encapsulation and testability, I'd rather go for the second. It's more important to have the correct code (i.e. produce the correct output) than a nice OOP design which doesn't work correctly, because it wasn't tested adequately. In Java, you can simply give the method "default" access and put the unit test in the same package. Unit tests are simply part of the package you're developing, and it's OK to have a dependency between the tests and the code which is being tested. It means that when you change the implementation, you may need to change your tests, but that's OK -- each change of the implementation requires re-testing the code, and if the tests need to be modified to do that, then you just do it.

In general, a class may be offering more than one interface. There is an interface for the users, and an interface for the maintainers. The second one can expose more to ensure that the code is adequately tested. It doesn't have to be a unit test on a private method -- it could be, for example, logging. Logging also "breaks encapsulation", but we still do it, because it's so useful.

share|improve this answer
3  
+1 Interesting point. In the end it's about maintainability, not adherence to the "rules" of good OOP. –  Phil Jul 17 '12 at 14:55
2  
+1 I completely agree with testability over encapsulation. –  Richard Nov 27 '12 at 10:44

Testing of private methods would depend on their complexity; some one line private methods wouldn't really warrant the extra effort of testing (this can also be said of public methods), but some private methods can be just as complex as public methods, and difficult to test through the public interface.

My preferred technique is to make the private method package private, which will allow access to a unit test in the same package but it will still be encapsulated from all other code. This will give the advantage of testing the private method logic directly instead of having to rely on a public method test to cover all parts of (possibly) complex logic.

If this is paired with the @VisibleForTesting annotation in the Google Guava library, you are clearly marking this package private method as visible for testing only and as such, it shouldn't be called by any other classes.

Opponents of this technique argue that this will break encapsulation and open private methods to code in the same package. While I agree that this breaks encapsulation and does open private code to other classes, I argue that testing complex logic is more important than strict encapsulation and not using package private methods which are clearly marked as visible for testing only must be the responsibility of the developers using and changing the code base.

Private method before testing:

private int add(int a, int b){
    return a + b;
}

Package private method ready for testing:

@VisibleForTesting
int add(int a, int b){
    return a + b;
}

Note: Putting tests in the same package is not equivalent to putting them in the same physical folder. Separating your main code and test code into separate physical folder structures is good practice in general but this technique will work as long as the classes are defined as in the same package.

share|improve this answer

First of all, as other authors suggested: think twice if you do really need to test private method. And if so, ...

In .NET you can convert it into "Internal" method, and make package "InternalVisible" to your unit test project.

In Java you can write tests itself in the class to be tested and your test methods should be able to call private methods as well. I don't really have big Java experience, so that's probably not the best practice.

Thanks.

share|improve this answer

If you really need to test private method, with Java I mean, you can use fest assert and/or fest reflect. It uses reflection.

Import the library with maven (given versions are not the lastest I think) or import it directly in your classpath:

<dependency>
     <groupId>org.easytesting</groupId>
     <artifactId>fest-assert</artifactId>
     <version>1.4</version>
    </dependency>

    <dependency>
     <groupId>org.easytesting</groupId>
     <artifactId>fest-reflect</artifactId>
    <version>1.2</version>
</dependency>

As an example, if you have a class named 'MyClass' with a private method named 'myPrivateMethod' which take a String as parameter an update its value to 'this is cool testing !', you can do the following junit test:

import static org.fest.reflect.core.Reflection.method;
...

MyClass objectToTest;

@Before
public void setUp(){
   objectToTest = new MyClass();
}

@Test
public void testPrivateMethod(){
   // GIVEN
   String myOriginalString = "toto";
   // WHEN
   method("myPrivateMethod").withParameterTypes(String.class).in(objectToTest).invoke(myOriginalString);
   // THEN
   Assert.assertEquals("this is cool testing !", myOriginalString);
}

This library also enables you to replace any bean properties (no matter they are private and no setters are written) by a mock, and using this with Mockito or any other mock framework is really cool. The only thing you have to know at the moment (don't know if this will be better in next versions) is the name of the target field / method you want to manipulate, and its signature.

share|improve this answer
2  
While reflection will enable you to test private methods, it is not good for detecting uses of them. If you change the name of a private method, this will break your test. –  Richard Nov 27 '12 at 10:42
1  
The test will break yes, but this is a minor issue from my point of view.Of course i fully agree about your explanation below on the package visibility (with tests classes in seperate folders but with same packages), but sometimes you don't really have the choice. For example if you have a really short mission in an enterprise which doesn't apply "good" methods (test classes not in the same package, etc.), if you don't have time to refactor existing code on which you are working / testing, this is still an good alternative. –  kij Nov 27 '12 at 11:14

What I normally do in C# is make my methods protected and not private. It's a slightly less private access modifier, but it hides the method from all classes that do not inherit from the class under test.

public class classUnderTest
{
   //this would normally be private
   protected void methodToTest()
   {
     //some code here
   }
}

Any class that doesn't inherit directly from classUnderTest has no idea that methodToTest even exists. In my test code, I can create a special testing class that extends and provides access to this method...

class TestingClass : classUnderTest
{
   public void methodToTest()
   {
     //this returns the method i would like to test
     return base.methodToTest();
   }
}

This class only exists in my testing project. Its sole purpose is to provide access to this single method. It allows me to access places that most other classes do not have.

share|improve this answer
3  
protected is part of the public API and incurs the same limitations (can never be changed, must be documented,...). In C# you can use internal together with InternalsVisibleTo. –  CodesInChaos Dec 13 '13 at 11:03

I usually make such methods protected. Let's say your class is in:

src/main/java/you/Class.java

You can create a test class as:

src/test/java/you/TestClass.java

Now you have access to protected methods and can unit test them (JUnit or TestNG doesnt really matter), yet you keep these methods from callers you did not want.

Note that this expects a maven-style source tree.

share|improve this answer

If you cannot use external APIs or dont want to, you can still use pure standard JDK API to access private methods using reflection. Here is an example

MyObject obj = new MyObject();
Method privateMethod = MyObject.class.getDeclaredMethod("getFoo", null);
privateMethod.setAccessible(true);
String returnValue = (String) privateMethod.invoke(obj, null);
System.out.println("returnValue = " + returnValue);

Check Java Tutorial http://docs.oracle.com/javase/tutorial/reflect/ or Java API http://docs.oracle.com/javase/7/docs/api/java/lang/reflect/package-summary.html for more information.

As @kij cited on his answer there are times when a simple solution using reflection is really good to test a private method.

share|improve this answer

Unit test case means testing the unit of code. It does not mean testing the interface because if you are testing the interface, that does not mean you are testing the unit of code. It becomes kind of a black box testing. Also, it is better to find issues on the smallest unit level than determining the issues on the interface level and then trying to debug that which piece was not working. Therefore, unit test case should be tested irrespective of their scope. Following is a way to test private methods.

If you are using java, you can use jmockit which provides Deencapsulation.invoke to call any private method of the class under testing. It uses reflection to call it eventually but provides a nice wrapper around it. (https://code.google.com/p/jmockit/)

share|improve this answer
    
how does this answer the question asked? –  gnat Feb 5 at 6:46
    
@gnat, The question was that What is the best way to unit test private methods in java classes? And my first point answers the question. –  agrawalankur Feb 5 at 19:46
    
your first point merely advertises a tool, but it doesn't explain why you believe it is better than alternatives, such as eg testing private methods indirectly as was suggested and explained in top answer –  gnat Feb 5 at 19:49

You can test private methods easily if you put your unit tests in an inner class on the class you are testing. Using TestNG your unit tests must be public static inner classes annotated with @Test, like this:

@Test
public static class UserEditorTest {
    public void test_private_method() {
       assertEquals(new UserEditor().somePrivateMethod(), "success");
    }
}

Since it's an inner class, the private method can be called.

My tests are run from maven and it automatically finds these test cases. If you just want to test one class you can do

$ mvn test -Dtest=*UserEditorTest

Source: http://www.ninthavenue.com.au/how-to-unit-test-private-methods

share|improve this answer
3  
You are suggesting including test code (and additional inner classes) in the actual code of the package that is deployed? –  MichaelT Apr 11 '13 at 3:36
1  
The test class is an inner class of the class you want to test. If you don't want those inner classes to be deployed you can just delete the *Test.class files from your package. –  Roger Keays Apr 11 '13 at 7:49
    
I don't love this option, but for many it's probably a valid solution, not worth the downvotes. –  Bill K May 8 '13 at 17:15
    
@RogerKeays: Technically when you do a deployment, how do you remove such "test inner classes"? Please don't say you cut them by hand. –  gyabraham Dec 13 '13 at 10:54
    
I don't remove them. Yes. I deploy code that is never executed at run time. It really is that bad. –  Roger Keays Dec 15 '13 at 1:14

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.