Because this is interactive, it will likely be hard to test well—or, at least, in a way that is readable.
One common way to test similar code would be to extract a method that takes in a Scanner and a PrintWriter, similar to this StackOverflow answer, and test that:
public void method() {
method(new Scanner(System.in), System.out);
}
/** For testing. */
public void method(Scanner scanner, PrintWriter output) {
output.println("Enter something");
int a = scanner.nextInt();
// ...
}
This is similar to assigning a new stdin/stdout using System.setIn
, but is much more predictable, and requires less cleanup. However, in both situations, methods like nextInt
will block while waiting for input. Unless you want to make this test multithreaded (which is complicated), you won't be able to read your output until the end, and you'll have to specify all of your instructions up front:
@Test
public void methodShouldLaunchTheSpaceShuttle() {
StringWriter output = new StringWriter();
String input = "5\n" // "Please enter another value!"
+ "10\n" // "Code accepted. Enter command:"
+ "Shuttle\n"; // "Launching space shuttle..."
systemUnderTest.method(new Scanner(input), new PrintWriter(output));
assertThat(output.toString(), contains("Please enter another value!"));
assertTrue(systemUnderTest.spaceShuttleLaunched());
}
That said, as long as your set of instructions is straightforward (and doesn't change), you can probably add comments (as above) and get a worthwhile test that increases your code coverage to what you need it to be.
(Note: Of course, rather than creating an overload method, you could also keep the "scanner" and "output" as mutable fields in your system under test. I tend to like keeping classes as stateless as possible, but that's not a very big concession if it matters to you or your coworkers/instructor.)