0

I have a class that is NetworkManager. I have a lot of private methods that I realy need to write test for them.

At first I didn't find any solution to write test for my private methods. Anyway I find a way to access my private methods and write some test for them.

I used Reflection to access my functions and write tests for them. there is an example of a simple private method:

 private String myFun (String input){
        return input+"hello";
    }

There is a test class that I used reflection in it:

@RunWith(AndroidJUnit4.class)
public class NetworkManagerTest {

    private static NetworkManager networkManager;
    private Context appContext = InstrumentationRegistry.getTargetContext();

    private @ADType
    int adType = ADType.TYPE_BANNER;


    @BeforeClass
    public static void setup() {

        getInstrumentation().runOnMainSync(new Runnable() {
            @Override
            public void run() {

                networkManager = NetworkManager.getInstance();
                networkManager.addNetworkCall(TestUtil.getSampleSystemRequest());

            }
        });
    }

    @Test
    public void sample() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {

        Method method = NetworkManager.class.getDeclaredMethod("myFun", String.class);
        method.setAccessible(true);
        String output = (String) method.invoke(networkManager, "Ehsan");

        Assert.assertEquals("Ehsanhello", output);
    }

}

This is works fine. But the question is how much is this way okay to write test for private methods with using of reflection?

Is there a better way to achieve this goal?

Ehsan
  • 2,676
  • 6
  • 29
  • 56

2 Answers2

2

But the question is how much is this way okay to write test for private methods with using of reflection?

Is there a better way to achieve this goal?

The most common approach is to abandon that goal.

Historically, the focus of TDD has been on verifying behaviors, not implementation details. Part of the point was that the tests give us the freedom to change the internal design of the code, confidently, because the tests will alert us to any unintended changes in behavior.

So if we need a test to ensure that the logic in some private method is correct, we find a use case for the public API that depends on that logic, and write tests that measure the behavior of the public API.

We can calibrate the test by injecting a temporary fault into the private method, and verifying that the test detects the fault.

Having done that, we have the option of refactoring the code by inlining the private method; all of the tests should still pass in that case, because we haven't changed the behavior of the test subject -- we've just moved the details around.

If you are going to be aggressively working to improve the internal design of your application, then you need tests that are decoupled from that internal design.

Community
  • 1
  • 1
VoiceOfUnreason
  • 52,766
  • 5
  • 49
  • 91
1

I am an enthusiast of saying that if you have too much private methods to test, it means that your class has too many responsibilities. Private methods could be grouped logically and extracted to other classes.

This is why I don't accept Guava's @VisibleForTesting annotation.

mate00
  • 2,727
  • 5
  • 26
  • 34