Java JUnit: test for user input (pass standard input to Scanner) - java

Issue: I'm trying to test a simple program in Java that requires user input but while I'm able to feed the input to the test, I'm only able to do so in the first called method. The error thrown is java.util.NoSuchElementException: No line found
The setup: The first method ask for user to type a command, after that and depending on the command the method will call on other methods that also ask for user input. This is where the issue arises.
Method to be tested:
public abstract class InputHandler {
// Scanner for commands, login message and instructions
public static void start() {
String fullCommand;
String actionCommand;
String commandId;
Scanner scanner = new Scanner(System.in);
// Command loop: asks for valid input and assigns id to variable if necessary
while(true) {
System.out.println("\nEnter command:");
actionCommand = scanner.nextLine().toLowerCase();
//logic to handle different length commands
}
switch (actionCommand) {
case "new lead":
newLead();
break;
case "show leads":
showLeads();
break;
case "quit":
try {
System.out.println("Goodbye!");
Thread.sleep(1000);
System.exit(0);
}catch (InterruptedException e) {
e.printStackTrace();
}
default:
System.out.println("Please enter a valid command");
}
}
}
JUnit Test:
#Test
void startTest() {
System.setIn(new ByteArrayInputStream("new lead\nGustavo Perez\n555555555\nhola#gus.io\nKurts".getBytes()));
InputHandler.start();
assertTrue(!DatabaseManager.getLeads().isEmpty());
}
Again the issue is on the test when the method is called, while it passes "new lead" as standard input (the first string in the byte array) to the Scanner, after the method start() calls the newLead() it no longer continues to pass the values in the byte array.
Thanks for any help!

Related

How do I Throw an IllegalArgumentException that won't terminate my program?

Ok so I have a method with a switch statement but I left out the rest of the cases because they're not important. In my main method, the operator method is called and passed the parameter "selection" in a while loop until they choose "Q".
When the user enters a negative number, it should throw an exception, print a message, and ignore their input but then loop back to the beginning. When this exception is thrown it terminates the program. Any help would be very much appreciated. Thanks!
public static void operator(String selection) throws IllegalArgumentException{
Scanner input = new Scanner(System.in);
double price;
switch(selection){
case "A":
System.out.println("Enter the price");
if(input.nextDouble()<0){
throw new IllegalArgumentException("Price cannot be a negative value");
}
else{
price = input.nextDouble();
}
break;
case"Q":
System.exit(0);
}
}
An IllegalArgumentException inherits from RuntimeException, for it not to stop your program you can just use a simple try{} catch {} but i don't recommend doing that with Runtime Exceptions. If that's the case, create your own Exception inheriting from java.lang.Exception.
You can use try catch here.
Something like this should work:
public static void operator(String selection) {
Scanner input = new Scanner(System.in);
double price;
switch(selection){
case "A":
System.out.println("Enter the price");
try {
if(input.nextDouble()<0) {
throw new NegativePriceException();
}
} catch (NegativePriceException e) {
System.out.println("The price can't be negative.");
e.printStackTrace();
}
price = input.nextDouble();
break;
case"Q":
System.exit(0);
}
}
And to make your own Exception class you basically need to inherit from Exception (if you want to use try catch on it) or inherit from RuntimeException (if you want it to stop your program from running), like this:
public class NegativePriceException extends Exception {
public NegativePriceException() {
super();
}
}
Java requires that you handle or declare all exceptions. If you are not handling an Exception using a try/catch block then it must be declared in the method's signature.
In your main method you should handle the Exception
public static void main(String args[]) {
//codes
try{
operator("A");
}
catch(IllegalArgumentException e){
e.printStackTrace();
}
}
You've gotten some good answers already on how to handle the exception.
For your case I don't think an exception is appropriate at all. You should get rid of the exception altogether and just handle the problem input by printing an error message and asking for a new input.
Exceptions are for exceptional situations, they should not be part of the normal execution of your code.

Java - Method structure execution

I am going through the University of Helsinki's Java course and I have a question on one of the examples.
The code in question:
import java.util.Scanner;
public class UserInterface {
private Scanner reader;
public UserInterface(Scanner reader) {
this.reader = reader;
}
public void start() {
while (true) {
String command = reader.nextLine();
if (command.equals("end")) {
break;
} else {
handleCommand(command);
}
}
}
public void handleCommand(String command) {
if (command.equals("buy")) {
String input = readInput("What to buy: ");
System.out.println("Bought!");
} else if (command.equals("sell")) {
String input = readInput("What to sell: ");
System.out.println("Sold!");
}
}
public String readInput(String question) {
while (true) {
System.out.print(question);
String line = reader.nextLine();
if (line.equals("carrot")) {
return line;
} else {
System.out.println("Item not found!");
}
}
}
}
If you choose to buy or sell something that isn't a carrot why does it not run the line directly below the input line in the handleCommand method (printing Bought! or Sold!)? I don't understand how it terminates the conditional in the case that a carrot is not bought or sold. How is the readInput method manipulating the handleCommand method here? Thanks.
The function readInput() is rather oddly defined: it will only return if you enter carrot.
readInput() contains a while loop that keeps looping until the user enters carrot, otherwise it says Item not found! and tries again. The output lines in handleCommand() are only executed when readInput() returns.
Basically your readInput() method returns the String "line" only if the user inputs "carrot" otherwise it will keep on going inside the else part and continue printing "Item not found!". But instead of System.out.println("Item not found!") ,
if you just return that statement then either "carrot" or "Item not found!" will be returned and stored in the "input" variable of handleCommand() method. In that case now it will print your "Bought!" or "Sold!" print statement irrespective whether you choose "carrot" or something else

Breaking Out Of A Loop Using A Method In Java

I am trying to use a method to double check before a user exits a while loop in my program.
private static Scanner input = new Scanner(System.in);
public static void ays() {
System.out.println("Are you sure?");
String ays = input.nextLine();
if (ays.equals("Yes")) {
break;
} else {
continue;
}
}
Upon running the program, I get the error break outside switch or loop, and continue outside switch or loop. Is there any way to achieve my goal here?
I guess you are invoking ays() inside a while loop. Let the return type of ays() be boolean and let it return either true or false. Invoke ays() from inside the while loop and based on the value returned by ays(), you continue or break out of the loop.
while (true) {
//Do Something
if (ays()) {
continue();
} else {
break();
}
}

Make Main Method restart/refresh

My code so far:
import java.util.*;
import java.util.Scanner.*;
public class Project{ // The Main Method
public static void main(String [] args){ // Creates the Main Method
System.out.println("Name a Method (Stability, efficiency ..)"); // Asks the user to select a method
Scanner scan = new Scanner(System.in); // Creates the Scanner
String splash = scan.nextLine(); // Transitions the user to the next line after choosing a method
if(splash.equals("efficiency")) // If users chooses Efficiency then it goes to the Efficiency method
{
efficiency(); // Calls the Efficiency method
}
if(splash.equals("Stability")) // If user chooses Stability then it goes to the Stability Method
{
stable(); // Calls the Stability method
}
else // What happens if the input wasnt recognized
{
System.out.println("I don't recognize this"); // what happens if an irrelevant method is chosen
}
}
}
How would I make it so that instead of:
else // What happens if the input wasnt recognized
{
System.out.println("I don't recognize this"); // what happens if an irrelevant method is chosen
}
It will refresh or restart the main method?
Wrap your code in a while loop which you leave when the user chooses the exit command:
public static void main(String [] args){
while (true) {
System.out.println("Name a Method (Stability, efficiency ..)");
Scanner scan = new Scanner(System.in);
String splash = scan.nextLine();
if (splash.equals("exit")) {
break;
} // else if (splash.equals("efficiency")) ...
}
}

JUnit testing with simulated user input

I am trying to create some JUnit tests for a method that requires user input. The method under test looks somewhat like the following method:
public static int testUserInput() {
Scanner keyboard = new Scanner(System.in);
System.out.println("Give a number between 1 and 10");
int input = keyboard.nextInt();
while (input < 1 || input > 10) {
System.out.println("Wrong number, try again.");
input = keyboard.nextInt();
}
return input;
}
Is there a possible way to automatically pass the program an int instead of me or someone else doing this manually in the JUnit test method? Like simulating the user input?
You can replace System.in with you own stream by calling System.setIn(InputStream in).
InputStream can be a byte array:
InputStream sysInBackup = System.in; // backup System.in to restore it later
ByteArrayInputStream in = new ByteArrayInputStream("My string".getBytes());
System.setIn(in);
// do your thing
// optionally, reset System.in to its original
System.setIn(sysInBackup);
Different approach can be make this method more testable by passing IN and OUT as parameters:
public static int testUserInput(InputStream in,PrintStream out) {
Scanner keyboard = new Scanner(in);
out.println("Give a number between 1 and 10");
int input = keyboard.nextInt();
while (input < 1 || input > 10) {
out.println("Wrong number, try again.");
input = keyboard.nextInt();
}
return input;
}
To test drive your code, you should create a wrapper for system input/output functions. You can do this using dependency injection, giving us a class that can ask for new integers:
public static class IntegerAsker {
private final Scanner scanner;
private final PrintStream out;
public IntegerAsker(InputStream in, PrintStream out) {
scanner = new Scanner(in);
this.out = out;
}
public int ask(String message) {
out.println(message);
return scanner.nextInt();
}
}
Then you can create tests for your function, using a mock framework (I use Mockito):
#Test
public void getsIntegerWhenWithinBoundsOfOneToTen() throws Exception {
IntegerAsker asker = mock(IntegerAsker.class);
when(asker.ask(anyString())).thenReturn(3);
assertEquals(getBoundIntegerFromUser(asker), 3);
}
#Test
public void asksForNewIntegerWhenOutsideBoundsOfOneToTen() throws Exception {
IntegerAsker asker = mock(IntegerAsker.class);
when(asker.ask("Give a number between 1 and 10")).thenReturn(99);
when(asker.ask("Wrong number, try again.")).thenReturn(3);
getBoundIntegerFromUser(asker);
verify(asker).ask("Wrong number, try again.");
}
Then write your function that passes the tests. The function is much cleaner since you can remove the asking/getting integer duplication and the actual system calls are encapsulated.
public static void main(String[] args) {
getBoundIntegerFromUser(new IntegerAsker(System.in, System.out));
}
public static int getBoundIntegerFromUser(IntegerAsker asker) {
int input = asker.ask("Give a number between 1 and 10");
while (input < 1 || input > 10)
input = asker.ask("Wrong number, try again.");
return input;
}
This may seem like overkill for your small example, but if you are building a larger application developing like this can payoff rather quickly.
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 processUserInput() {
processUserInput(new Scanner(System.in), System.out);
}
/** For testing. Package-private if possible. */
public void processUserInput(Scanner scanner, PrintWriter output) {
output.println("Give a number between 1 and 10");
int input = scanner.nextInt();
while (input < 1 || input > 10) {
output.println("Wrong number, try again.");
input = scanner.nextInt();
}
return input;
}
Do note that you won't be able to read your output until the end, and you'll have to specify all of your input up front:
#Test
public void shouldProcessUserInput() {
StringWriter output = new StringWriter();
String input = "11\n" // "Wrong number, try again."
+ "10\n";
assertEquals(10, systemUnderTest.processUserInput(
new Scanner(input), new PrintWriter(output)));
assertThat(output.toString(), contains("Wrong number, try again.")););
}
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.
You might also choose to put your test code in the same Java package as the code under test (even if it's in a different source folder), which allows you to relax the visibility of the two parameter overload to be package-private.
I managed to find a simpler way. However, you have to use external library System.rules by #Stefan Birkner
I just took the example provided there, I think it couldn't have gotten more simpler:
import java.util.Scanner;
public class Summarize {
public static int sumOfNumbersFromSystemIn() {
Scanner scanner = new Scanner(System.in);
int firstSummand = scanner.nextInt();
int secondSummand = scanner.nextInt();
return firstSummand + secondSummand;
}
}
Test
import static org.junit.Assert.*;
import static org.junit.contrib.java.lang.system.TextFromStandardInputStream.*;
import org.junit.Rule;
import org.junit.Test;
import org.junit.contrib.java.lang.system.TextFromStandardInputStream;
public class SummarizeTest {
#Rule
public final TextFromStandardInputStream systemInMock
= emptyStandardInputStream();
#Test
public void summarizesTwoNumbers() {
systemInMock.provideLines("1", "2");
assertEquals(3, Summarize.sumOfNumbersFromSystemIn());
}
}
The problem however in my case my second input has spaces and this makes the whole input stream null!
You might start by extracting out the logic that retrieves the number from the keyboard into its own method. Then you can test the validation logic without worrying about the keyboard. In order to test the keyboard.nextInt() call you may want to consider using a mock object.
I have fixed the problem about read from stdin to simulate a console...
My problems was I'd like try write in JUnit test the console to create a certain object...
The problem is like all you say : How Can I write in the Stdin from JUnit test?
Then at college I learn about redirections like you say System.setIn(InputStream) change the stdin filedescriptor and you can write in then...
But there is one more proble to fix... the JUnit test block waiting read from your new InputStream, so you need create a thread to read from the InputStream and from JUnit test Thread write in the new Stdin... First you have to write in the Stdin because if you write later of create the Thread to read from stdin you likely will have race Conditions... you can write in the InputStream before to read or you can read from InputStream before write...
This is my code, my english skill is bad I hope all you can understand the problem and the solution to simulate write in stdin from JUnit test.
private void readFromConsole(String data) throws InterruptedException {
System.setIn(new ByteArrayInputStream(data.getBytes()));
Thread rC = new Thread() {
#Override
public void run() {
study = new Study();
study.read(System.in);
}
};
rC.start();
rC.join();
}
I've found it helpful to create an interface that defines methods similar to java.io.Console and then use that for reading or writing to the System.out. The real implementation will delegate to System.console() while your JUnit version can be a mock object with canned input and expected responses.
For example, you'd construct a MockConsole that contained the canned input from the user. The mock implementation would pop an input string off the list each time readLine was called. It would also gather all of the output written to a list of responses. At the end of the test, if all went well, then all of your input would have been read and you can assert on the output.

Categories

Resources