views:

11449

answers:

24

How do I use jUnit to test a class that has internal private methods? It seems bad to change the access modifier for a method just to be able to run a test. Thanks.

+63  A: 

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:

  1. The private method is dead code
  2. There is a design smell near the class that you are testing
  3. The method that you are trying to test should not be private
Trumpi
Disagree. It's totally valid to have an algorithm in a private method which needs more unit testing than is practical through a class's public interfaces.
Mr. Shiny and New
Hey Mr ShinyYes, but then you will have brittle tests. Also, see number 2 in my reply.
Trumpi
I don't understand why testing a private method creates code smell? Is not the point of unit testing to test each small part to isolate errors.could you explain what a brittle test is please?
Ben Page
A brittle test is a test which fails too easily when there's a change in the code. Generally this happens when the test result is based on what the method does rather than on the expected outputs and side-effects given a set of inputs. Ideally, a change to the code which does not change the results should not break the test.
@Mr. Shiny and New: If your private method is complex enough to warrant independent unit testing, then it's complex enough to have its own class. The class can be internal of course (i.e. not accessible from other packages).
sleske
+11  A: 

Generally a unit test is intended to exercise the public interface of a class or unit, private methods therefore are implementation detail that you would not expect to test explicitly.

John Channing
+15  A: 

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.

Thomas Owens
+21  A: 

From this link, you basically have 4 options:

  • Don't test private methods.
  • Give the methods package access.
  • Use a nested test class.
  • Use reflection.
Iker Jimenez
A: 

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

Dalroth
A: 

I'd use Reflection, since I don't like the idea of changing the access to package on the declared method just for the sake of testing. However, I usually just test the public methods which should also ensure the the private methods are working correctly.

Edit:

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 this answer.

Josh Brown
A: 

@Josh, you can't use reflection to get private methods from outside the owner class, the private modifier affects reflection also

Here's a good article on the question's subject

Juan Manuel
+82  A: 

If you have somewhat of a legacy application and you're not allowed to change the visibility of your methods, best way to test private methods is to use Reflection. Internally we're using helpers to get/set private and private static variables as well as invoke private and private static methods. The following patterns will let you do pretty much anything related to the private methods and fields. Of course you can't change private static final variables through Reflection.

Method method = targetClass.getDeclaredMethod(methodName, argClasses);
method.setAccessible(true);
return method.invoke(targetObject, argObjects);

And for fields:

Field field = targetClass.getDeclaredField(fieldName);
field.setAccessible(true);
field.set(object, value);

Notes:
* targetClass.getDeclaredMethod(methodName, argClasses) lets you look into private methods. Same thing applies for getDeclaredField.
* The setAccessible(true) is required to play around with privates.

Cem Catikkas
Pretty useful indeed, thanks for the info
Hoffmann
Useful if you don't know the API perhaps, but if you are having to test private methods in this manner there is something up with your design. As another poster says unit testing should test the class's contract: if the contract is too broad and instantiates too much of the system then the design should be addressed.
andygavin
Very useful. Using this it is important to keep in mind that it would fail badly if tests were run post obfuscation.
Rick Minerich
True... Anything Reflective will fail miserably after obfuscation.
Cem Catikkas
+6  A: 

EDIT: Having tried Cem Catikkas' solution using reflection, I'd have to say his was a more elegant solution than I have described here. However, if you're looking for an alternative to using reflection, and have access to the source you're testing, this will still be an option.

There is possible merit in testing private methods of a class, particularly with test driven development, where you would like to design small tests before you write any code.

Creating a test with access to private members and methods can test areas of code which are difficult to target specifically with access only to public methods. If a public method has several steps involved, it can consist of several private methods, which can then be tested individually.

Advantages:

  • can test to a finer granularity

Disadvantages:

  • test code must reside in the same file as source code, which can be more difficult to maintain
  • similarly with .class output files, they must remain within the same package as declared in source code

However, if continuous testing requires this method, it may be a signal that the private methods should be extracted, which could be tested in the traditional, public way.

Here is a convoluted example of how this would work:

// import statements and package declarations

public class ClassToTest 
{
    private int decrement(int toDecrement) {
     toDecrement--;
     return toDecrement;
    }

    // constructor and rest of class

    public static class StaticInnerTest extends TestCase
    {
     public StaticInnerTest(){
      super();
     }

     public void testDecrement(){
      int number = 10;
      ClassToTest toTest= new ClassToTest();
      int decremented = toTest.decrement(number);
      assertEquals(9, decremented);
     }

     public static void main(String[] args) {
      junit.textui.TestRunner.run(StaticInnerTest.class);
     }

    }
}

Inner class would be compiled to ClassToTest$StaticInnerTest.

See also: http://www.javaworld.com/javaworld/javatips/jw-javatip106.html

Grundlefleck
+8  A: 

If you're trying to test existing code that you're reluctant or unable to change, reflection is a good choice.

If the class's design is still flexible and you've got a complicated private method that you'd like to test separately, I suggest you pull it out into a separate class and test that class separately. This doesn't have to change the public interface of the original class, it can internally create an instance of the helper class and call the helper method.

If you want to test difficult error conditions coming from the helper method, you can go a step further. Extract an interface from the helper class, add a public getter and setter to the original class to inject the helper class (used through its interface), and then inject a mock version of the helper class into the original class to test how the original class responds to exceptions from the helper. This approach is also helpful if you want to test the original class without also testing the helper class.

Don Kirkby
+3  A: 

If you want to test private methods of a legacy application where you can't change the code, one option is jMockit, which will allow you to create mocks to an object even when they're private to the class.

Will Sargent
+21  A: 

When I have private methods in a class that is sufficiently complicated that I feel the need to test the private methods directly, that is a code smell: my class is too complicated.

My usual approach to addressing it is to tease out a new class that contains the interesting bits. Often, this method and the fields it interacts with, and maybe another method or two can be extracted in to a new class.

The new class exposes these methods as 'public', so they're accessible for unit testing. The new and old classes are now both simpler than the original class, which is great for me (I need to keep things simple, or I get lost!).

Note that I'm not suggesting that anyone create classes without using their brain! The point here is to use the forces of unit testing to help you find good new classes.

Jay Bazuzi
+3  A: 

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.

Darren Greaves
+4  A: 

Since you're using JUnit, have you looked at junit-addons? It has the ability to ignore the java security model and access private methods and attributes.

Joe
+3  A: 

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 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 pass-thru.

Aaron
Because often a particular piece of code from a public method is refactored into an internal private method and is really the critical piece of logic which you might have got wrong. You want to test this independently from the public method
oxbow_lakes
+3  A: 

Testing Private Methods breaks the encapsulation of your class beacuse every time you change the internal implementation you break client code (in this case the tests). So don't test private methods.

ema
+2  A: 

You should definately look into PowerMock, it just recently hit 1.0!

"PowerMock uses a custom classloader and bytecode manipulation to enable mocking of static methods, constructors, final classes and methods, private methods, removal of static initializers and more."

Probably the best addition to Mockito I've found to test legacy code.
rcl
+5  A: 

As others have said... don't test private methods directly. Here are a few thoughts:

  1. keep all methods small and focused (easy to test, easy to find what is wrong)
  2. use code coverage tools, I like this one (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.

TofuBeer
A: 

@Juan Manuel

You can turn off access restrictions for reflection so that private means nothing. The setAccessible(true) call does that. The only restriction is that a ClassLoader may disallow you from doing that.

Here is a link to an article on doing this in Java

TofuBeer
A: 

In C# you could have used System.Reflection, though in Java I don't know. Though I feel the urge to answer this anyway since if you "feel you need to unit test private methods" my guess is that there is something else which is wrong...

I would seriously consider looking at my architecture again with fresh eyes....

Thomas Hansen
A: 

What if your test classes are in the same package as the class that should be tested ?

But in a different directory of course, src & classes for your source code, test/src and test/classes for your test classes. And let be classes and test/classes be in your classpath.

Diego Amicabile
+3  A: 

I have used Reflection to do this 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 Objects internals. If another developer wants to make a small internal change to the class, which doesn't affect the classes public contract, he 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.

Jon
A: 

Just two examples of where I would want to test a private method:

  1. Decryption routines - I would not want to make them public just for the sake of testing, else anyone can use them to decrypt. But they are intrinsic to the code, complicated, and need to always work.
  2. Creating an SDK for community consumption. Here public takes on a wholly different meaning, since this is code that the whole world may see (not just internal to my app). I put code into private methods if I don't want the SDK users to see it - I don't see this as code smell, merely as how SDK programming works. But of course I still need to test my private methods, and they are where the functionality of my SDK actually lives.

I understand the idea of only testing the "contract". But I don't see one can advocate actually not testing code - ymmv.

So my tradeoff involves complicating the JUnits with reflection, rather than compromising my security & SDK.

Richard Le Mesurier
+2  A: 

check this article : Testing Private Methods with JUnit and SuiteRunner

Mona