261

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?

8
  • 2
    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
  • 42
    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
  • 3
    Both public and private methods should be tested. Hence, a test driver generally needs to be inside the class it tests. like this. May 28 '15 at 10:08
  • 3
    @Rig -- +1 -- you should be able to invoke all the required behavior of a private method from your public methods -- if you cannot then the functionality can never be invoked anyway so there is no point in testing it. May 28 '15 at 10:40
  • 1
    This article was useful for me enterprisecraftsmanship.com/posts/unit-testing-private-methods
    – frederj
    Feb 24 '20 at 18:28

13 Answers 13

320

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.

20
  • 44
    +1 bazillion. And if a private method is never called, don't unit-test it, delete it! Aug 14 '11 at 6:08
  • 336
    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
  • 43
    @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
  • 81
    This answer DOES NOT answer the question. The question is how should private methods be tested, not whether they should be tested. Whether a private method should be unit tested is an interesting question and worthy of debate, but not here. The appropriate response is add a comment in the question stating that testing private methods may not be a good idea and give a link to a separate question which would go into the matter more deeply.
    – TallGuy
    Jan 30 '14 at 22:39
  • 19
    @TallGuy Allow me to distill my answer here to its core point. The answer to "how does one unit test private methods?" is "One doesn't."
    – Adam Lear
    Jan 30 '14 at 22:40
149

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.

2
  • 15
    +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
  • 13
    +1 I completely agree with testability over encapsulation.
    – Richard
    Nov 27 '12 at 10:44
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.

3
  • @VisibleForTesting actually helped.
    – iCantC
    Mar 31 '20 at 4:57
  • @VisibleForTesting is also in androidx.annotation, which comes with just about every AndroidX library. Apr 6 '20 at 15:39
  • but why cannot the method call cannot compile saying it's private?
    – Lei Yang
    Sep 21 '20 at 6:41
19

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.

3
  • This seems highly inapprobiate. How do you handle automatic refactoring in your 116 tests now? manually?
    – Wisienkas
    Nov 12 '19 at 10:13
  • @Wisienkas Use an (at)see tag in the javadoc for your unit test, when the automatic refactoring updates, it will update the javadoc - the test will fail and the answer will be locally apparent. Ideally the dev would review their commit (diff) prior and update the string that was missed (near the changed javadoc). Apr 2 '20 at 13:21
  • This approach never gets old, right? Is this approach still legit? May 27 '20 at 11:07
12

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.

10

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/)

4
  • how does this answer the question asked?
    – gnat
    Feb 5 '14 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. Feb 5 '14 at 19:46
  • 1
    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 '14 at 19:49
  • jmockit has moved and the old official page points to an article about "Synthetic Urine and Artificial Pee". Wich is by the way still related to mocking stuff, but not relevant here :) The new official page is: jmockit.github.io
    – Guillaume
    Aug 19 '19 at 12:12
8

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.

3

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.

2
  • 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
2

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.

1
  • 4
    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. Dec 13 '13 at 11:03
2

This section from the book Clean Code, in Chapter 10 Classes > Class Organization > Encapsulation kinda implies that testing on private method is a pseudo-proposition.

We like to keep our variables and utility functions private, but we're not fanatic about it. Sometimes we need to make a variable or utility functions protected so that it can be accessed by a test. For us, tests rule. If a test in the same package needs to call a function or access a variable, we'll make it protected or package scope. However, we'll first look for a way to maintain privacy. Loosening encapsulation is always the last resort.

IMHO private method is just a wrapper of a partial responsibility implementation, which is invoked in non-private method. So if testing on a private method is very important, the access scope should be enlarged so that a unit test framework like JUnit is able to run test on it. Otherwise, the only way to "test" private method is in fact the test on a non-private method, which calls that private method

Moreover, the Deencapsultion class of JMockit was removed last year. This kinda proved that "test on private method" is a pseudo-proposition

2

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: https://rogerkeays.com/how-to-unit-test-private-methods

5
  • 4
    You are suggesting including test code (and additional inner classes) in the actual code of the package that is deployed?
    – user40980
    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. Apr 11 '13 at 7:49
  • 1
    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. 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. Dec 15 '13 at 1:14
0

In Swift or Objective-C, you mark the method as @testable. The compiler knows when it compiles unit tests (because the end product is not an application or library but a "unit test" executable), and in that case allows calling private methods marked as @testable as if they were public. The advantage of this system is that your methods stay as private as you want them except for unit tests (where normal rules don't apply) and you don't need any code changes or preprocessor tricks or similar to support this.

I think other languages have similar features.

0

As another answer mentions, you can use a nested class, but I want to explain why you might want to do this.

For logic code that has been made dependency-free (ie: not UI code, not database code, etc.), theoretically you should not do this. Dependency-free code is basically an API, and you "should" be able to hit all of the code through that API, even the private stuff. If you can't access some of the private stuff through the public interface, then what is that code even doing?

However, for UI and other kinds of presentation code (reports), this is not the case. A part of the "interface" of this type of code is the user's physical interface with the computer. This means that fully encapsulated UI code cannot be directly tested programmatically, because it is not a programmatic interface.

I have found, at least so far, that a clean approach that allows testing this kind of code is to use a nested class. Create a "Tester" class nested within the class you want to test that takes a reference to an instance of that class. Then, as needed, write some simple methods that will tell you things about the state of the UI.

There are two extremes that I would suggest avoiding. First, don't put the unit tests themselves into the nested Tester class. Second, don't just expose the internals of the class through the Tester. Use the Tester to give you simple but meaningful answers about questions you have about the UI, or possibly instructions about how to manipulate the UI. Basically these methods will be a kind of replacement/stand-in for the user.

(Note that two things make this a little cleaner in C# than in Java. C# has conditional compilation, so you can wrap your Tester class in #if DEBUG and leave it out of your release version. Also, C# has partial classes, so you can put nested classes in their own files.)

Here is a rough pseudo-Java example since I don't really do this in Java:

(note: in my UI code I use the convention that UI fields get a 'c' prefix)

public class SomethingWindow extends SomeUIClass {
   final TextBox cTextBox1;
   final TextBox cTextBox2;
   final ListBox<Item> cListBox;
   final CheckBox cHideSomeBox;

   ...

   public class Tester {
      final SomethingWindow mWindow;

      public Tester(SomethingWindow window) {
         mWindow = window;
      }

      public void HideSome() { mWindow.cHideSomeBox.Checked = true; }   
      public Item[] GetLoadedItems() { return mWindow.cListBox.GetItems(); }
      public void SetTextBox1Text(String text) { mWindow.cTextBox1.Text = text; }
      public String GetTextBox2Text() { return mWindow.cTextBox2.Text; }
      public boolean GetTextBox2IsReadOnly() { return mWindow.cTextBox2.ReadOnly; }
  }
}

And your unit tests might look something like this:

@Test
public void Test_HidingSomeWorks() {
   var context = new TestContext();
   // add stuff to context or something
   var window = new SomethingWindow(context);
   window.Init();
   var tester = new SomethingWindow.Tester(window);
   tester.HideSome();

   var result = tester.GetLoadedItems();

   // assert that the expected items have been returned
   // ie: that the right ones have been filtered away
}

@Test
public void Test_RelatedTextBoxes() {
   var context = new TestContext();
   var window = new SomethingWindow(context);
   var tester = new SomethingWindow.Tester(window);
   tester.SetTextBox1Text("some text");

   var result = tester.GetTextBox2Text();

   // assert something about the result
}

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