0

First of all, I tried to look for some solution in this cool site. I have found a question relating to my issue, but my tests still fails. The question I found, can be found here: JUnit testing with simulated user input

Let's see my implementation:

I have an user interaction service class which read then validate the user inputs: UserInteractionService.java

package Services;

import java.util.Scanner;

public class UserInteractionService {

    private static Scanner scanner = new Scanner(System.in);

    public static int readIntegerAndValidate() {
        while (!scanner.hasNextInt()) {
            System.out.println("It is not a valid integer number. Try again!");
            scanner.next(); 
        }
        return scanner.nextInt();

    }

    public static double readDoubleAndValidate() {
        while (!scanner.hasNextDouble()) {
            System.out.println("It is not a valid number. Try again!");
            scanner.next(); 
        }
        return scanner.nextDouble();
    }
}

And, of course, I have a test class for this service class: UserInteractionServiceTest.java

@Test
public void userWriteInput_checkIfItIsInteger_userTypedInteger() {
    String inputData = "5";
    System.setIn(new ByteArrayInputStream(inputData.getBytes()));
    int input = readIntegerAndValidate();
    assertEquals(5, input);
}

@Test
public void userWriteDouble_checkIfItIsDouble_userTypedDouble() {
    String inputData = "5.3";
    System.setIn(new ByteArrayInputStream(inputData.getBytes()));
    double input = readDoubleAndValidate();
    assertEquals(5.3, input, 0);
}

Well, my second test function (userWriteDouble_checkIfItIsDouble_userTypedDouble) fails, and I could not find the reason... As you can see I used the same pattern like in de first test. What is your opinion, why does this test fail? Shall I use some mocking framework (Mockito)? Thanks in advance for the answers!

Failure Trace:

java.util.NoSuchElementException
    at java.util.Scanner.throwFor(Unknown Source)
    at java.util.Scanner.next(Unknown Source)
    at Services.UserInteractionService.readDoubleAndValidate(UserInteractionService.java:21)
    at Services.UserInteractionServiceTest.userWriteDouble_checkIfItIsDouble_userTypedDouble(UserInteractionServiceTest.java:23)
...
Community
  • 1
  • 1
mirind4
  • 1,423
  • 4
  • 21
  • 29

2 Answers2

2

You've made it harder to test your code by making the scanner static. I would consider giving UserInteractionService a constructor that takes a Scanner. I suggest EasyMock and the code in test would look like

import static org.easymock.EasyMock.*;

Scanner scanner = createMock(Scanner.class);
expect(scanner.hasNextDouble()).and return(true).once();
expect(scanner.nextDouble()).and return(5.3).once();

replay(scanner);

And the service you call in your test would be a

new UserInteractionService (scanner)
Willcodeforfun
  • 361
  • 3
  • 10
  • 1
    Thanks! Well, it is not necessary to have a static scanner. Actually I use Mockito, so I try to solve it with this. I think I have to write almost the same with Mockito, so if it works, I will accept your answer! ;) – mirind4 Apr 02 '16 at 15:03
  • aah i have problem because I can not mock the Scanner class with Mocikto. With Mockito the static or final classes can not be mocked. I think I will change to BefferedReader in my implementation – mirind4 Apr 02 '16 at 17:34
1

Don't use a static field for the Scanner. It stores the reference to the System.in when it is created the first time. Setting System.in again to a different value in the second test does not change the Scanner's System.in. Change your class code like this fixes your test.

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

By the way you should restore System.in after the test. I've written a library named System Rules that makes it even easier to write tests for code that reads from System.in.

Stefan Birkner
  • 24,059
  • 12
  • 57
  • 72
  • Hey! Thanks for your answer, I upvoted it! Well, I have changed the code, but now the console waits for my input. It seems that the setIn() does not set value I gave to :\ What is your opinion? Thanks in advance for your help! – mirind4 Apr 07 '16 at 14:51
  • 1
    You have to call `setIn` before you create the `UserInteractionService`. Are you doing it in this order? – Stefan Birkner Apr 08 '16 at 08:12
  • Works like a charm! Thanks for the additional information! ;) – mirind4 Apr 10 '16 at 13:35