Advertisement
Advertisement


How do I test a private function or a class that has private methods, fields or inner classes?


Question

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.

2019/10/15
1
2777
10/15/2019 3:07:13 PM

Accepted Answer

Update:

Some 10 years later perhaps the best way to test a private method, or any inaccessible member, is via @Jailbreak from the Manifold framework.

@Jailbreak Foo foo = new Foo();
// Direct, *type-safe* access to *all* foo's members
foo.privateMethod(x, y, z);
foo.privateField = value;

This way your code remains type-safe and readable. No design compromises, no overexposing methods and fields for the sake of tests.

If you have somewhat of a legacy Java application, and you're not allowed to change the visibility of your methods, the 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:
1. TargetClass.getDeclaredMethod(methodName, argClasses) lets you look into private methods. The same thing applies for getDeclaredField.
2. The setAccessible(true) is required to play around with privates.

2019/03/15
1664
3/15/2019 2:50:55 AM

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
2008/08/29

When I have private methods in a class that are 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 such issues 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 people create classes without using their brain! The point here is to use the forces of unit testing to help you find good new classes.

2016/05/19

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.

2017/12/14

From this article: Testing Private Methods with JUnit and SuiteRunner (Bill Venners), you basically have 4 options:

  1. Don't test private methods.
  2. Give the methods package access.
  3. Use a nested test class.
  4. Use reflection.
2020/04/22

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.

2012/12/29