0

I have built an interactive java app using Scanner class. I want to test it with Junit 5.

After searching a but I wrote the test case for simulating the shell. The test case runs for the first command and remains stuck in the main method. It doesn't return the console out. My subsequent commmands are not executed due to it.

public static void main(String[] args) {

  final Scanner scanner = new Scanner(System.in);

    while (true) {
        final String input = scanner.nextLine();
        if (input.equalsIgnoreCase("exit")) {
          printMsg("Exiting the application..");
          System.exit(1);
        }
        else {
          printMsg("User Input >>>> " + input);
          final CommandProcessor commandProcessor = new CommandProcessor();
          try {
            commandProcessor.process(input);
          }
          catch (Exception e) {
            System.out.println("An error occurred - " e.getLocalizedMessage() + ". Please try again.");
          }
        }
    }
}


public class CommandProcessor {

  public void process(final String input) throws Exception {
      //Some validations

      final CommandHandler commandHandler = CommandHandlerFactory.getHandler(inputCommand);
      commandHandler.execute(args);
    }
  }

}

public class CreateCommandHandler extends CommandHandler {

  @Override
  void handle(final String[] args) throws Exception {
    final int units = Integer.parseInt(args[1]);
    System.out.println("Created units " + units);
  }
}


class ApplicationTest {
  private static final InputStream systemIn = System.in;
  private static final PrintStream systemOut = System.out;

  private static InputStream testIn;
  private static OutputStream testOut;

  @BeforeEach
  public void setUpOutput() {
    testOut = new ByteArrayOutputStream();
    System.setOut(new PrintStream(testOut));
  }

  private void provideInput(String data) {
    testIn = new ByteArrayInputStream(data.getBytes());
    System.setIn(testIn);
  }

  private String getOutput() {
    return testOut.toString();
  }

  @AfterEach
  public void resetSystemInputOutput() {
    System.setIn(systemIn);
    System.setOut(systemOut);
  }

  @Test
  public void testCreateSuccess() {
    String testString = "create 2";
    provideInput(testString);

    Application.main(new String[0]);

    assertEquals("Created units - 2", getOutput());

    //Verifying the empty state. Another handler is invoked for it.
    provideInput("status");
    assertEquals("No units assigned", getOutput());

    //exiting the shell.
    provideInput("exit");
  }

//  @Test
  public void testStatusAfterCreateParkingLotSuccess() {
    String testString = "status";
    provideInput(testString);

    Application.main(new String[0]);

    assertEquals(AppConstants.PARKING_LOT_IS_EMPTY, getOutput());

    resetSystemInputOutput();

    provideInput("exit");

    Application.main(new String[0]);
  }

  @AfterAll
  public static void exit() {
    //System.setIn(new ByteArrayInputStream("exit".getBytes()));
  }
}

The unit test, testCreateSuccess(), runs only the create command and then it keeps waiting for the next input. The control is not returning back to the test to send the next command. Why is it behaving different here? When I run the shell I can enter commands 1 by 1. How can I achieve the same behaviour in the test cases? There any 5-6 commands which I need to run and verify using Junit. Any help is appreciated. I also want to process these commands from a txt file.

Johannes Kuhn
  • 14,778
  • 4
  • 49
  • 73
jay
  • 171
  • 4
  • 13
  • 1
    Great, you want to test your code. However, you're going about this the wrong way. Instead of simulating a scanner for your tests, you should write tests that don't rely on scanning for input. You can do this by extracting your logic into functions and testing those instead. Unit tests shouldn't be affected by the input/output mechanisms – byxor Oct 21 '19 at 10:34
  • @byxor I had thought of the same alternative. I was thinking on how do I cover the main method. – jay Oct 21 '19 at 11:45
  • You can do that with an integration test and mocking – byxor Oct 21 '19 at 11:49

0 Answers0