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)
...
4
  • I would usually mock the Scanner, yes. What is the test failure output? Commented Apr 2, 2016 at 14:44
  • @Willcodeforfun Thanks for your comment! I edited my answer with the Failure Trace. So you say that mocking of scanner would be a good idea. How would the solution look like? Commented Apr 2, 2016 at 14:51
  • you said that the second test fails, does the first one pass? Commented Apr 2, 2016 at 14:57
  • Yes, the first one pass successfully Commented Apr 2, 2016 at 14:59

2 Answers 2

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)
Sign up to request clarification or add additional context in comments.

2 Comments

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! ;)
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
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.

3 Comments

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!
You have to call setIn before you create the UserInteractionService. Are you doing it in this order?
Works like a charm! Thanks for the additional information! ;)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.