How can I use JUnit to test a class with private methods or fields without changing access modifiers?

How can I use JUnit to test a class that contains internal private methods, fields, or nested classes? Changing the access modifiers of methods seems undesirable in facilitating testing. How can I test JUnit private methods effectively?

Hey MattD,

Test Through Public Methods: Test private methods indirectly by testing the public methods that use them. This approach is the most straightforward and ensures that the private methods are tested as part of the class’s functionality.

Example:

public class MyClass { public int publicMethod() { return privateMethod() * 2; }

private int privateMethod() {
    return 5;
}

}

// JUnit test @Test public void testPublicMethod() { MyClass myClass = new MyClass(); assertEquals(10, myClass.publicMethod()); }

Advantages:

No need to change access modifiers. Ensures that private methods are tested within the context of the class’s functionality.

Hello MattD,

Use Reflection: Use Java Reflection to access and invoke private methods, fields, or nested classes. This approach allows you to bypass Java’s access control checks.

Example:

import java.lang.reflect.Method;

public class MyClass { private int privateMethod() { return 5; } }

// JUnit test @Test public void testPrivateMethod() throws Exception { MyClass myClass = new MyClass(); Method method = MyClass.class.getDeclaredMethod(“privateMethod”); method.setAccessible(true); int result = (int) method.invoke(myClass); assertEquals(5, result); }

Advantages:

Directly tests private methods. Useful for methods that are not easily accessible through public APIs.

Hello MattD

Here is your answer,

Use a Testing Framework or Library: Use a testing framework or library designed to facilitate the testing of private methods. Some libraries, like PowerMock(GitHub - powermock/powermock: PowerMock is a Java framework that allows you to unit test code normally regarded as untestable.), extend Mockito and JUnit to handle private methods, static methods, and other tricky cases.

import org.junit.Test; import org.junit.runner.RunWith; import org.powermock.api.mockito.PowerMockito; import org.powermock.core.classloader.annotations.PrepareForTest; import org.powermock.modules.junit4.PowerMockRunner;

@RunWith(PowerMockRunner.class) @PrepareForTest(MyClass.class) public class MyClassTest {

@Test
public void testPrivateMethod() throws Exception {
    MyClass myClass = PowerMockito.spy(new MyClass());
    PowerMockito.when(myClass, "privateMethod").thenReturn(5);
    int result = myClass.publicMethod(); // Use the public method to trigger private method
    assertEquals(10, result); // Assuming publicMethod uses privateMethod
}

}

Advantages:

Provides more control over private methods and fields. Can handle complex cases like static methods and constructors.