By MattGrommes


2008-08-29 16:11:09 8 Comments

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.

30 comments

@m.nguyencntt 2020-07-24 07:46:22

Detail my sample with lombok as below. private field, private method:

public static void main(String[] args) throws NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException, NoSuchMethodException, InvocationTargetException {
    Student student = new Student();

    Field privateFieldName = Student.class.getDeclaredField("name");
    privateFieldName.setAccessible(true);
    privateFieldName.set(student, "Naruto");

    Field privateFieldAge = Student.class.getDeclaredField("age");
    privateFieldAge.setAccessible(true);
    privateFieldAge.set(student, "28");

    System.out.println(student.toString());

    Method privateMethodGetInfo = Student.class.getDeclaredMethod("getInfo", String.class, String.class);
    privateMethodGetInfo.setAccessible(true);
    System.out.println(privateMethodGetInfo.invoke(student, "Sasuke", "29"));
}


@Setter
@Getter
@ToString
class Student {
  private String name;
  private String age;

  private String getInfo(String name, String age) {
    return name + "-" + age;
  }
}

@Victor Grazi 2018-01-24 20:08:28

PowerMockito is made for this. Use maven dependency

    <dependency>
        <groupId>org.powermock</groupId>
        <artifactId>powermock-core</artifactId>
        <version>2.0.7</version>
        <scope>test</scope>
    </dependency>

Then you can do

import org.powermock.reflect.Whitebox;
...
MyClass sut = new MyClass();
SomeType rval = Whitebox.invokeMethod(sut, "myPrivateMethod", params, moreParams);

@Ahmed Hussein 2020-06-29 06:53:04

In your class:

namespace my_namespace {
    #ifdef UNIT_TEST
        class test_class;
    #endif

    class my_class {
        public:
            #ifdef UNIT_TEST
                friend class test_class;
            #endif
        private:
            void fun() { cout << "I am private" << endl; }
    }
}

In your unit test class:

#ifndef UNIT_TEST
    #define UNIT_TEST
#endif

#include "my_class.h"

class my_namespace::test_class {
    public:
        void fun() { my_obj.fun(); }
    private:
        my_class my_obj;
}

void my_unit_test() {
    test_class test_obj;
    test_obj.fun(); // here you accessed the private function ;)
}

@Iker Jimenez 2008-08-29 16:16:20

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.

@Pacerier 2015-08-21 07:03:25

@JimmyT., Depends on who the "production code" is for. I would call code produced for applications stationed within VPN whose target users are sysadmins to be production code.

@Jimmy T. 2015-08-21 20:27:01

@Pacerier What do you mean?

@user2441441 2016-07-12 21:05:46

5th option, like mentioned above is testing the public method that calls the private method? Correct?

@user2918461 2017-09-20 15:32:56

@LorenzoLerate I've been wrestling with this because I'm doing embedded development and I'd like my software to be as small as possible. Size constraints and performance is the only reason I can think of.

@Aguid 2017-10-27 21:13:24

I really like the test using reflection: Here the pattern Method method = targetClass.getDeclaredMethod(methodName, argClasses); method.setAccessible(true); return method.invoke(targetObject, argObjects);

@Trenton 2020-04-22 23:33:33

@user2441441 that's the same as #1 — don't test private methods

@Abhishek Sengupta 2020-03-13 17:42:24

Hey use this utility class if you are on spring.

ReflectionTestUtils.invokeMethod(new ClassName(), "privateMethodName");

@Vishwas 2020-01-16 02:29:32

If you are only using Mockito:

You can consider the private method as a part of public method being tested. You can make sure you cover all the cases in private method when testing public method.

Suppose you are a mockito only user(You are not allowed or don't want to use Powermock or reflection or any such tools) and you dont want to change the existing code or libraries being tested, this might be the best way.

The only thing you need to handle if you choose this way is the variables(user defined objects) declared locally within private methods. If the private method depends on locally declared variable objects and their methods, make sure you declare those user defined objects globally as private object instead of locally declared objects. You can instantiate these objects locally .

This allows you to mock these objects and inject them back to testing object. You can also mock(using when/then) their methods.

This will allow you test private method without errors when testing the public method.

Advantages 1. code coverage 2. Able to test the complete private method.

Disadvantages 1. Scope of the Object - If you don't want the object to be exposed to other methods within same class, this might not be your way. 2. You might end up testing the private method multiple times when invoked at different public methods and/or in same method multiple times.

@WesternGun 2019-05-12 14:27:33

PowerMock.Whitebox is the best option I have seen, but when I read its source code, it reads private fields with reflection, so I think I have my answer:

  • test private internal states(fields) with PowerMock, or just reflection without the overhead of introducing another independency
  • for private methods: actually, the upvote for this question itself, and the huge number of comments and answers, shows that it is a very concurrent and controversial topic where no definite answer could be given to suit every circumstance. I understand that only contract should be tested, but we also have coverage to consider. Actually, I doubt that only testing contracts will 100% make a class immune to errors. Private methods are those who process data in the class where it is defined and thus does not interest other classes, so we cannot simply expose to make it testable. I will try not to test them, but when you have to, just go for it and forget all the answers here. You know better your situation and restrictions than any other one in the Internet. When you have control over your code, use that. With consideration, but without over-thinking.

After some time, when I reconsider it, I still believe this is true, but I saw better approaches.

First of all, Powermock.Whitebox is still usable.

And, Mockito Whitebox has been hidden after v2(the latest version I can find with Whitebox is testImplementation 'org.mockito:mockito-core:1.10.19') and it has always been part of org.mockito.internal package, which is prone of breaking changes in the future(see this post). So now I tend not to use it.

In Gradle/Maven projects, if you define private methods or fields, there is no other ways then reflection to get access to them, so the first part stays true. But, if you change the visibility to "package private", the tests following the same structure in test package will have access to them. That is also another important reason why we are encouraged to create the same hierarchy in main and test package. So, when you have control over production code as well as tests, delete that private access modifier may be the best option for you because relatively it does not cause huge impact. And, that makes testing as well as private method spying possible.

@Autowired
private SomeService service; // with a package private method "doSomething()"

@Test
void shouldReturnTrueDoSomething() {
    assertThat(doSomething(input), is(true)); // package private method testing
}

@Test
void shouldReturnTrueWhenServiceThrowsException() {
    SomeService spy = Mockito.spy(service); // spying real object
    doThrow(new AppException()).when(spy).doSomething(input); // spy package private method
    ...

}

When it comes to internal fields, in Spring you have ReflectionUtils.setField().

At last, sometimes we can bypass the problem itself: if there is a coverage requirement to meet, maybe you can move these private methods into an inner static class and ignore this class in Jacoco. I just found some way to ignore inner class in Jacoco gradle tasks. another question

@Mukundhan 2019-10-18 13:53:33

The following Reflection TestUtil could be used generically to test the private methods for their atomicity.

import com.google.common.base.Preconditions;

import org.springframework.test.util.ReflectionTestUtils;

/**
 * <p>
 * Invoker
 * </p>
 *
 * @author
 * @created Oct-10-2019
 */
public class Invoker {
    private Object target;
    private String methodName;
    private Object[] arguments;

    public <T> T invoke() {
        try {
            Preconditions.checkNotNull(target, "Target cannot be empty");
            Preconditions.checkNotNull(methodName, "MethodName cannot be empty");
            if (null == arguments) {
                return ReflectionTestUtils.invokeMethod(target, methodName);
            } else {
                return ReflectionTestUtils.invokeMethod(target, methodName, arguments);
            }
        } catch (Exception e) {
           throw e;
        }
    }

    public Invoker withTarget(Object target) {
        this.target = target;
        return this;
    }

    public Invoker withMethod(String methodName) {
        this.methodName = methodName;
        return this;
    }

    public Invoker withArguments(Object... args) {
        this.arguments = args;
        return this;
    }

}

Object privateMethodResponse = new Invoker()
  .withTarget(targetObject)
  .withMethod(PRIVATE_METHOD_NAME_TO_INVOKE)
  .withArguments(arg1, arg2, arg3)
  .invoke();
Assert.assertNotNutll(privateMethodResponse)

@avtomaton 2019-08-15 18:32:43

For C++ (since C++11) adding the test class as a friend works perfectly and does not break production encapsulation.

Let's suppose that we have some class Foo with some private functions which really require testing, and some class FooTest that should have access to Foo's private members. Then we should write the following:

// prod.h: some production code header

// forward declaration is enough
// we should not include testing headers into production code
class FooTest;

class Foo
{
  // that does not affect Foo's functionality
  // but now we have access to Foo's members from FooTest
  friend FooTest;
public:
  Foo();
private:
  bool veryComplicatedPrivateFuncThatReallyRequiresTesting();
}
// test.cpp: some test
#include <prod.h>

class FooTest
{
public:
  void complicatedFisture() {
    Foo foo;
    ASSERT_TRUE(foo.veryComplicatedPrivateFuncThatReallyRequiresTesting());
  }
}

int main(int /*argc*/, char* argv[])
{
  FooTest test;
  test.complicatedFixture();  // and it really works!
}

@Xeverous 2019-08-26 18:37:38

There is also a template trick which allows to get to private members (through some pointer indirection IIRC) or just -fno-access-control (which just ignores private and protected restrictions).

@yoAlex5 2019-07-12 15:50:52

Android has @VisibleForTesting annotation from android.support.annotation package.

The @VisibleForTesting annotation indicates that an annotated method is more visible than normally necessary to make the method testable. This annotation has an optional otherwise argument that lets you designate what the visibility of the method should have been if not for the need to make it visible for testing. Lint uses the otherwise argument to enforce the intended visibility.

On the practice it means that you should make a method open for testing and the @VisibleForTesting annotation will show a warning.

For example

package com.mypackage;

public class ClassA {

    @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
    static void myMethod() {

    }
}

And when you call ClassA.myMethod() within the same package(com.mypackage) you will see the warning.

enter image description here

@Ercan 2019-04-09 08:23:32

There is another approach to test your private methods. If you "enable assertion" in run configurations then you can unit test your method inside method itself. For example;

assert ("Ercan".equals(person1.name));
assert (Person.count == 2);

@Cem Catikkas 2008-08-29 16:35:11

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.

@andygavin 2009-06-26 14:23:29

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.

@Rick Minerich 2010-02-04 01:11:36

Very useful. Using this it is important to keep in mind that it would fail badly if tests were run post obfuscation.

@Cem Catikkas 2010-02-04 18:26:46

True... Anything Reflective will fail miserably after obfuscation.

@Rob 2011-07-01 10:56:50

The example code didn't work for me, but this made thigs clearer: java2s.com/Tutorial/Java/0125__Reflection/…

@despot 2011-08-04 11:56:51

This is all great (I've been doing the same for a long time), but there is one glitch that I am trying to find the solution for. Imagine that u wanna test the exception outcome of the private method. Instead of the method invocation giving u an IllegalArgumentException, for example, you'll get null Class:java.lang.reflect.InvocationTargetException. Maybe there is a way of covering this, but I am not familiar with it. A colegue of mine proposed using powermock for it.

@Michael Piefel 2011-10-25 07:22:54

Much better than using reflection directly would be to use some library for it such as Powermock.

@T-Bull 2013-06-23 12:01:33

@despot: According to the doc, you should be able to retrieve the original exception via getTargetException() or getCause().

@Thorbjørn Ravn Andersen 2013-07-18 18:46:25

This is why Test Driven Design is helpful. It helps you figure out what needs to be exposed in order to validate behavior.

@Asim Ghaffar 2013-09-01 10:59:43

Here is an example for MyAdder.sum(int, int) --- MyAdder object = new MyAdder(); Method method = MyAdder.class.getDeclaredMethod("sum", new Class[] { Integer.TYPE, Integer.TYPE }); method.setAccessible(true); Object r = method.invoke(object, new Object[] { 1, 2 }); Assert.assertEquals(3l, ((Integer) r).longValue());

@JBoy 2013-11-29 09:57:36

shouldn't that be getClass().getDeclaredMethod() ?

@juanmf 2016-03-04 13:10:08

Legacy or not, you shouldn't change visibility for testing purposes. +1 to Reflection in any case.

@Rogério 2016-06-03 16:02:50

It's sad to see such a terribly wrong answer like this get so many upvotes. One should not reduce the accessibility of methods or fields, neither access them through Reflection. I have written literally thousands of JUnit/TestNG over many years, and I never had to resort to testing private methods directly. Occasionally, I had to read a private field (through Reflection), but that was about it. I guess some developers (many, apparently) are too lazy to write proper tests (which only call public methods), and prefer to cheat by using Reflection.

@Jonathan Neufeld 2016-09-01 17:10:01

No I don't think appealing to TDD is a valid criticism here. Why should a unit test intended to cover a private method be excluded from that encapsulation? If TDD is supposed to tell you to make that method public, you're not producing quality code here, instead you're appeasing a logical flaw in the language itself.

@mike rodent 2016-10-23 19:43:14

Few of these replies and comments appear to have picked on this: the question could have been about approaches to legacy code, except that the OP has included the TDD tag. I don't have a huge amount of TDD experience yet, but if you study the "seminal" Growing Obj-Oriented Software Guided by Tests, I think it becomes clear: private methods should result from refactoring and only from refactoring. By definition refactoring means that the code has passed the relevant tests. So I think the question is why this TDD tag was included.

@Espen 2016-10-27 23:55:49

testing private methods should be done from public members, private members that are not invoked directly or indirectly by public members have no value. Unit testing and TDD is not about directly testing every method written, it is about testing the behavior of the written code compared to the requirements for writing that code.

@mvreijn 2016-12-01 11:17:06

Most purists fail to acknowledge that there are legitimate cases for this. My case: I am writing a plug-in for a (closed source) commercial product. Writing regular unit tests for public methods involves mocking large parts of that product, and there are limits to this approach. Being able to test my private methods in the manner described above ensures that 95% of my code has been tested before deployment.

@Daniel 2017-10-10 16:59:08

This guys provides a more in-depth explanation youtu.be/agnblS47F18?t=24m23s. Check at 24:23 for a solution similar to the example above.

@ACV 2017-11-30 13:00:58

One problem with testing private methods with reflection is that if you delete your method, you won't see it in the tests at compile time.

@WesternGun 2019-05-12 14:23:33

PowerMock Whitebox reads private fields with reflection. So I think I have my answer: test private internal states with PowerMock, or just reflection without the overhead of introducing another independency, and private methods: don't test.

@Miladinho 2017-10-29 19:01:35

I'd like to contribute that of you are worried by not testing private methods as many of the posts suggest, consider that a code coverage tool will determine exactly how much of your code is tested and where it leaks, so it is quantifiably acceptable to do this.

I am going to say something that needs to be said but many may not like to hear. Those of you contributing answers that direct the author of the question towards a 'work around' are doing a massive disservice to the community. Testing is a major part of all engineering disciplines, you would not want to buy a car that is not properly tested, and tested in a meaningful way, so why would anyone want to buy or use software that is tested poorly? The reason people do this anyways is probably because the effects of badly tested software are felt way after the fact, and we don't usually associate them with bodily harm. This is a very dangerous perception which will be difficult to change, but it is our responsibility to deliver safe products regardless of what even management is bullying us to do. Think Equifax hack...

We must strive to build an environment that encourages good software engineering practices, this does not mean ostracizing the weak/lazy among us who do not take their craft seriously, but rather, to create a status quo of accountability and self reflection that would encourage everyone to pursue growth, both mentally and skillfully. I am still learning, and may have wrong perceptions/opinions myself, but I do firmly believe that we need to hold ourselves accountable to good practices and shun irresponsible hacks or workarounds to problems.

@Constantinos 2017-10-29 19:25:25

You make good points (some/most of which have already been made by others), but please try to avoid antagonizing by using words such as "pseudo developers/engineers". As you said (and I agree), we should not ostracize, but instead create a better status quo and help everyone to learn and improve.

@Miladinho 2019-01-07 19:52:55

@Constantinos Thanks for pointing that out. I recall when I was writing this response that I was frustrated at the lack of resources (or perception thereof) to learn good practices. Having barely graduated college at that time, I was seeking a criterion that could guide me on how to write good code. I agree that the language I used was not ok and I have edited that out. Thank you.

@Louis Saglio 2018-12-13 19:40:20

You can create a special public method to proxy the private method to test. The @TestOnly annotation is out of the box available when using IntelliJ. The downside is is that if somebody want to to use the private method in a public context, he can do it. But he will be warned by the annotation and the method name. On IntelliJ a warning will appear when doing it.

import org.jetbrains.annotations.TestOnly

class MyClass {

    private void aPrivateMethod() {}

    @TestOnly
    public void aPrivateMethodForTest() {
        aPrivateMethod()
    }
}

@AR1 2018-09-22 09:47:51

If you have a case where you really need to test a private method/class etc.. directly, you can use reflection as already mentioned in other answers. However if it comes to that, instead of dealing directly with reflection I'd rather use util classes provided by your framework. For instance, for Java we have:

As per how to use them, you can find plenty of articles online. Here one that I particularly liked:

@HilaB 2018-06-28 11:19:32

My team and I are using Typemock, which has an API that allows you to fake non-public methods. Recently they added the ability to fake non-visible types and to use XUnit.

@seyed mohammad madani 2018-01-10 07:56:47

In c++ : before including class header that has a private function that you want test it

Use this code:

#define private public
#define protected public

@Franz D. 2018-07-05 14:32:11

Ouch. I guess it works fine, but I'd prefer using friend declarations instead of messing around with #defines on such a basic level.

@Matt Messersmith 2018-08-15 01:58:23

Yeah that'll work...but holy **** is that (likely) awful for your design

@AndersK 2019-02-25 07:19:06

FYI this no longer works in VS2019, it is not allowed to use macros that way any longer.

@Android is everything for me 2017-11-23 11:34:00

Best and proper legal way to test Java private method from test framework is @VisibleForTesting annotation over the method so same method will be visible for test framework as like public method.

@TofuBeer 2009-02-14 18:54:45

You can turn off Java 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.

See Subverting Java Access Protection for Unit Testing (Ross Burton) for a way to do this in Java.

@Josh Brown 2008-08-29 16:30:03

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.

@juan 2008-08-29 16:34:15

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

@tc. 2013-03-22 20:03:36

@jmfsg The article you link to link to specifically says "Testing private methods is a little more involved; but we can still do it using System.Reflection." (Apparently you need ReflectionPermission, but that's not normally a problem.)

@Snicolas 2013-09-17 20:23:50

Today, I pushed a Java library to help testing private methods and fields. It has been designed with Android in mind, but it can really be used for any Java project.

If you got some code with private methods or fields or constructors, you can use BoundBox. It does exactly what you are looking for. Here below is an example of a test that accesses two private fields of an Android activity to test it:

@UiThreadTest
public void testCompute() {

    // Given
    boundBoxOfMainActivity = new BoundBoxOfMainActivity(getActivity());

    // When
    boundBoxOfMainActivity.boundBox_getButtonMain().performClick();

    // Then
    assertEquals("42", boundBoxOfMainActivity.boundBox_getTextViewMain().getText());
}

BoundBox makes it easy to test private/protected fields, methods and constructors. You can even access stuff that is hidden by inheritance. Indeed, BoundBox breaks encapsulation. It will give you access to all that through reflection, BUT everything is checked at compile time.

It is ideal for testing some legacy code. Use it carefully. ;)

https://github.com/stephanenicolas/boundbox

@forhas 2013-10-02 14:12:14

Just tried it, BoundBox is a simple and elegant and solution!

@Joe 2008-09-11 22:20:28

If you're using JUnit, have a look at junit-addons. It has the ability to ignore the Java security model and access private methods and attributes.

@Will Sargent 2008-09-09 03:50:56

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.

@Domenic D. 2013-11-19 04:22:57

As part of the jmockit library, you have access to the Deencapsulation class which makes testing private methods easy: Deencapsulation.invoke(instance, "privateMethod", param1, param2);

@MedicineMan 2017-11-20 05:38:36

I use this approach all the time. Very helpful

@Grundlefleck 2008-09-01 20:58:47

Having tried Cem Catikkas' solution using reflection for Java, 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 the rest of the 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);
        }
    }
}

The inner class would be compiled to ClassToTest$StaticInnerTest.

See also: Java Tip 106: Static inner classes for fun and profit

@phareim 2011-01-12 10:27:21

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

@skia.heliou 2015-01-15 13:12:59

Be sure to download the entire JUnit-addons (sourceforge.net/projects/junit-addons) package, not the Source Forge-Recommended Project PrivateAccessor.

@skia.heliou 2015-01-20 19:40:28

And be sure that, when you're using a Class as your first parameter in these methods, that you're accessing only static members.

@Jon 2009-06-25 10:01:12

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.

@Colin M 2013-07-08 13:27:26

+1 to this. In my opinion it's the best answer to the question. By testing private methods you are testing the implementation. This defeats the purpose of unit testing, which is to test the inputs/outputs of a class' contract. A test should only know enough about the implementation to mock the methods it calls on its dependencies. Nothing more. If you can not change your implementation without having to change a test - chances are that your test strategy is poor.

@Aaron Marcus 2015-04-02 16:21:48

@Colin M That's not really what he's asking though ;) Let him decide it, you don't know the project.

@ACV 2017-11-30 11:32:47

Not really true. It could take a lot of effort to test a small part of the private method through the public method using it. The public method could require significant setup before you reach the line that calls your private method

@wuppi 2019-07-02 07:43:30

I agree. You should test, if the contract is fulfilled. You should not test, how this is done. If the contact is fulfilled without reaching 100% code coverage (in private methods), that might be dead or useless code.

@Rahul 2017-09-08 17:36:58

You can use PowerMockito to set return values for private fields and private methods that are called/used in the private method you want to test:

Eg. Setting return value for private method:

MyClient classUnderTest = PowerMockito.spy(new MyClient());

//Set expected return value
PowerMockito.doReturn(20).when(classUnderTest, "myPrivateMethod", anyString(), anyInt());
//This is very important otherwise it will not work
classUnderTest.myPrivateMethod(); 

//Setting private field value as someValue:
Whitebox.setInternalState(classUnderTest, "privateField", someValue);

Then finally you can validate your private method under test is returning correct value based on set values above by:

String msg = Whitebox.invokeMethod(obj, "privateMethodToBeTested", "param1");
Assert.assertEquals(privateMsg, msg);

Or

If classUnderTest private method does not return value but it set another private field then you can get that private field value to see if it was set correctly:

//To get value of private field
MyClass obj = Whitebox.getInternalState(classUnderTest, "foo");
assertThat(obj, is(notNull(MyClass.class))); // or test value

@GROX13 2016-08-29 21:10:59

I would suggest you refactoring your code a little bit. When you have to start thinking about using reflection or other kind of stuff, for just testing your code, something is going wrong with your code.

You mentioned different types of problems. Let's start with private fields. In case of private fields I would have added a new constructor and injected fields into that. Instead of this:

public class ClassToTest {

    private final String first = "first";
    private final List<String> second = new ArrayList<>();
    ...
}

I'd have used this:

public class ClassToTest {

    private final String first;
    private final List<String> second;

    public ClassToTest() {
        this("first", new ArrayList<>());
    }

    public ClassToTest(final String first, final List<String> second) {
        this.first = first;
        this.second = second;
    }
    ...
}

This won't be a problem even with some legacy code. Old code will be using an empty constructor, and if you ask me, refactored code will look cleaner, and you'll be able to inject necessary values in test without reflection.

Now about private methods. In my personal experience when you have to stub a private method for testing, then that method has nothing to do in that class. A common pattern, in that case, would be to wrap it within an interface, like Callable and then you pass in that interface also in the constructor (with that multiple constructor trick):

public ClassToTest() {
    this(...);
}

public ClassToTest(final Callable<T> privateMethodLogic) {
    this.privateMethodLogic = privateMethodLogic;
}

Mostly all that I wrote looks like it's a dependency injection pattern. In my personal experience it's really useful while testing, and I think that this kind of code is cleaner and will be easier to maintain. I'd say the same about nested classes. If a nested class contains heavy logic it would be better if you'd moved it as a package private class and have injected it into a class needing it.

There are also several other design patterns which I have used while refactoring and maintaining legacy code, but it all depends on cases of your code to test. Using reflection mostly is not a problem, but when you have an enterprise application which is heavily tested and tests are run before every deployment everything gets really slow (it's just annoying and I don't like that kind of stuff).

There is also setter injection, but I wouldn't recommended using it. I'd better stick with a constructor and initialize everything when it's really necessary, leaving the possibility for injecting necessary dependencies.

@Loduwijk 2017-03-09 18:46:20

Disagree with the ClassToTest(Callable) injection. That makes ClassToTest more complicated. Keep it simple. Also, that then requires someone else to tell ClassToTest something that ClassToTest should be the boss of. There is a place for injecting logic, but this is not it. You have just made the class harder to maintain, not easier.

@Loduwijk 2017-03-09 18:49:02

Also, it is preferable if your method of testing X does not increase X complexity to the point where it might cause more problems... and therefore require additional testing... which if you've implemented in a way that can cause more problems... (this is not an infinite loops; each iteration is likely smaller than the one before it, but still annoying)

@GROX13 2017-03-09 18:52:40

Could you explain why would it make class ClassToTest harder to maintain? Actually it makes your application easier to maintain, what do you suggest making new class for every different value you'll need in first and 'second' variables?

@GROX13 2017-03-09 18:54:47

Method of testing doesn't increase complexity. It's just your class which is poorly written, so poorly that it can't be tested.

@Loduwijk 2017-03-09 21:59:28

Harder to maintain because the class is more complicated. class A{ A(){} f(){} } is simpler than class A { Logic f; A(logic_f) } class B { g() { new A( logic_f) } }. If that were not true, and if it were true that supplying a class' logic as constructor arguments were easier to maintain, then we would pass all logic as constructor arguments. I just don't see how you can claim class B{ g() { new A( you_dont_know_your_own_logic_but_I_do ) } } ever makes A easier to maintain. There are cases where injecting like this makes sense, but I don't see your example as "easier to maintain"

@Loduwijk 2017-03-09 22:06:25

As for "what do you suggest making new class for every different value you'll need"... I don't understand how that follows. No. I'm saying keep it simple. class A { M m; N n; f() { } } super simple. Don't break from that unless you have a reason. If you had to in order to test private members, sure, fine; I just don't see how you can claim it is "easier to maintain." Dependency injection only makes things easier to maintain when it reduces complexity (decouples classes, makes graphs/charts easier to follow, something), which it did not in your example.

@Loduwijk 2017-03-09 22:07:55

Note that I am not suggesting that your actual answer is invalid. Supplying the logic from the outside can in fact answer the original question. I am only commenting on a specific statement within the answer, a statement which the answer does not hinge on.

@Loduwijk 2017-03-09 22:13:46

Actually, on third (or fourth?) read over, I see I may have missed a point. In your no-arg public ClassToTest() { this(...); }, is that implying that the class no-arg constructor is generally used, that it can supply its own logic known internally to the class, and the other constructor used only for testing (or if B wants to change its behavior for some reason; a handy side effect)? I did not catch that the first couple reads over.

@Loduwijk 2017-03-09 22:19:54

Yes, I gotcha now. The fact that you do not have a default implementation known internally to ClassToTest threw me off, but you do have it implied by the ellipse. For some reason, I was originally thinking you intended that the logic must be supplied only from the outside. For suckers like me, could you just edit the "..." to be something like "defaultLogic"; assuming I understand you correctly now.

@Legna 2016-06-03 15:47:49

A quick addition to @Cem Catikka's comment, when using ExpectedException:

Keep in mind that your expected exception will be wrapped in an InvocationTargetException, so in order to get to your exception you will have to throw the cause of the InvocationTargetException you received. Something like (testing private method validateRequest() on BizService):

@Rule
public ExpectedException thrown = ExpectedException.none();

@Autowired(required = true)
private BizService svc;


@Test
public void testValidateRequest() throws Exception {

    thrown.expect(BizException.class);
    thrown.expectMessage(expectMessage);

    BizRequest request = /* Mock it, read from source - file, etc. */;
    validateRequest(request);
}

private void validateRequest(BizRequest request) throws Exception {
    Method method = svc.getClass().getDeclaredMethod("validateRequest", BizRequest.class);
    method.setAccessible(true);
    try {
        method.invoke(svc, request);
    }
    catch (InvocationTargetException e) {
        throw ((BizException)e.getCause());
    }
 }

@Olcay Tarazan 2016-06-02 11:52:01

Please see below for an example;

The following import statement should be added:

import org.powermock.reflect.Whitebox;

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");

Related Questions

Sponsored Content

7 Answered Questions

[SOLVED] C# "internal" access modifier when doing unit testing

34 Answered Questions

[SOLVED] How do you assert that a certain exception is thrown in JUnit 4 tests?

21 Answered Questions

[SOLVED] Running unittest with typical test directory structure

  • 2009-12-13 16:10:23
  • Major Major
  • 229829 View
  • 734 Score
  • 21 Answer
  • Tags:   python unit-testing

27 Answered Questions

[SOLVED] Java inner class and static nested class

35 Answered Questions

15 Answered Questions

[SOLVED] How do I run all Python unit tests in a directory?

31 Answered Questions

[SOLVED] How do you unit test private methods?

33 Answered Questions

[SOLVED] Making a private method public to unit test it...good idea?

  • 2011-08-16 09:11:42
  • jcvandan
  • 41396 View
  • 306 Score
  • 33 Answer
  • Tags:   c# java unit-testing

Sponsored Content