Home > Software engineering >  How to test a private method in Java when testing through public API is ugly?
How to test a private method in Java when testing through public API is ugly?

Time:10-03

I have a Java program which reads user commands from the terminal (until he types exit) and performs some computation.

The code looks as follows:

public static void main(String[] args) {
    String command = read_from_stdin();
    while (!command.equals("exit")) {
        String output = execute(command)
        System.out.println(output);
        command = read_from_stdin();
    }
}

private String execute(String command) {...}

The question is: how do I test the private execute method?

  1. Test through the public main function. That requires to feed the input into the main program not from the terminal but from some file. Probably this test will be not a Java Unit test, rather some shell script. YUCK.

  2. Make execute public and write Java test for it. Doesn't this break the idea of using private/public access modifiers?

Any other ideas?

UPDATE

Several comments suggest to refactor execute into a separate class. So if I do something like this:

class Executor {
    public String execute(String command) {...}
}

class Main {
    public static void main(String[] args) {
        Executor executor = new Executor();
        String command = read_from_stdin();
        while (!command.equals("exit")) {
            String output = executor.execute(command);
            System.out.println(output);
            command = read_from_stdin();
        }
    }
}

Then sure, I can now Unit-test the public Executor api. But isn't this conceptually the same as making execute public (and if not the same, then why is this better)?

CodePudding user response:

You are not supposed to test private methods, it's like you testing that something is implemented in a concrete way, instead of testing functionality. If you need to test something private, then there is good chance it should have been public in the first place. Looking at your example, this looks like the case to me.

I would refactor the code, before starting tests.

  1. Make an executor for each command. Now you can test each executor separately for correct handling of the command.
  2. Make some kind of dispatcher/strategy/factory, which instantiates the correct executor for the command. You can now test the logic, if the correct executor has been chosen.

Edit: To address your additional question, this is not conceptually the same as simply changing the access modifier. Currently your main class has at least 3 responsibilities - input/output, choosing correct logic to execute depending on command and executing said logic. This violates the single responsibility principle from SOLID:

There should never be more than one reason for a class to change. In other words, every class should have only one responsibility.

This approach is better because it will make the code adhere more to the principles of writing easily extensible and easily maintainable code.

CodePudding user response:

Usual practice is to extract method in separate class and test that class.

CodePudding user response:

Sometimes you dont want to go the extra mile of extracting everything out. Sometimes you cannot go for best practices for various reasons.

A good solution to this problem is to make the method package private (remove private). If your test is in the same package, then you can access that method and test it directly.

I would personally also add @VisibleForTesting to make clear that this method is accessible because of testing reasons.

In general this is sometimes which is rarely done and always points to some wrong designs.

  • Related