javainputjunitjunit3

JUnit testing layout


I have a specific dictionary project that takes in user inputs and writes them to a database. The inputs (for now) are taken in through scanners (System.in) and I have multiple cases for example:

  1. Enter word and definition
  2. Enter synonyms
  3. Print dictionary

Things like this. How can I replicate user inputs with JUnit?


Solution

  • GhostCat is right. I would like completing its answer.

    In your application, there are 2 distinct responsibilities :

    Good design tries to avoid mixing responsibilities. So, you should create a class for :

    What is the advantage of it ?
    The logic of your application is now in the class processing the logic.
    In this way, you can concentrate unit test on this class to check that your application handle the logic as expected.

    With a design like it, You don't need to worry about the scanner since it's a mature component which works : you don't need to unit test it works.

    -- Edit : For answering your comment about how to realize an integration test with System.in

    I looked the code.
    First, with your actual code, you could not do an integration test with scanner which relies on multiple inputs captured because classic mocking tools as Mockito doesn't allow to do it (class is final).
    You can stub the inputstream but as in the same method, you take multiple inputs (option selection + values), you cannot stubbed the two inputs.
    So, we have to find a trick for bypassing it. A way to handle the problem is creating two ways of using your application : one with input entered one by one by user and another with all inputs entered in one time with delimiters for your unit test.

    All is not operational but you can follow the principle.

    The unit test will be like that :

    @Test
    public void printOptionWithAddedWordInDictionary() throws Exception {
      final ByteArrayInputStream inputStreamStubbed = new   ByteArrayInputStream("a|dog|super animal!".getBytes());
      InputReceiver inputReceiver = new InputReceiver(inputStreamStubbed, "\\|");
      inputReceiver.printOptions();
    }
    

    And as you see, you have two constructors now and two new private fields :

    private InputStream inputStream;
    private Scanner input;
    
    public InputReceiver() {
      inputStream = System.in;
      scanner = new Scanner(inputStream);
    }
    
      // for unit testing
     InputReceiver(InputStream inputStream, String delimiter) {
      this.inputStream = inputStream;
      scanner = new Scanner(inputStream);
      scanner.useDelimiter(delimiter);
    }
    

    The second is package private for testing.