public class Test
{
public static void main(String[] args) throws FileNotFoundException
{
Scanner input = new Scanner("text.txt");
int x = input.nextInt();
}
}
text.txt being:
8
8
6
7
This code throws a InputMismatch Exception. Why?
That is because "text.txt" is not a number. Try:
Scanner input = new Scanner(new File("text.txt"));
The constructor Scanner(String) accepts a String to read from, not a file name.
So, nextInt() is trying to read an int from the String you pass to it, ie. "text.txt".
Instead, use the constructor that accepts a File source, Scanner(File).
The problem is due to overloading. You are calling new Scanner(String) instead of new Scanner(File). If you tried scanner.next() you would see it returns "text.txt"
Related
I'm very new in Java, and for practicing I'm trying to make a program that generates new, random words using some values (mostly letters). The program is meant to take these values from a text file. The next step is to define inventories (Arrays) that contain each letter of its kind (first by defining a variable (int) for the length of each array, and then filling each array with its proper letters (String)). While checking my progress, I realize that my code isn't updating the inventories lengths (cInv and vInv).
This is the relevant part of the code:
static File language;
static Scanner scanFile;
static Scanner scanInput = new Scanner(System.in);
static int cInv;
static int vInv;
//Getters go here
public static void setLanguage(File language) {Problem.language = language;}
public static void setCInv(int CInv) {Problem.cInv = cInv;}
public static void setVInv(int VInv) {Problem.vInv = vInv;}
//Asks for the file with the language values.
public static void takeFile() throws FileNotFoundException {
String route = scanInput.nextLine();
setLanguage(new File(route));
BufferedReader br;
br = new BufferedReader(new FileReader(language));
}
//Gathers the language values from the file.
public static void readFile() throws FileNotFoundException {
takeFile();
scanFile = new Scanner(language);
//Defines the inventory sizes. It seems the failure is here.
if (scanFile.hasNextInt()) {setCInv(scanFile.nextInt());}
if (scanFile.hasNextInt()) {setVInv(scanFile.nextInt());}
}
public static void main(String[] args) throws FileNotFoundException {
readFile();
//The following line is for checking the progress of my coding.
System.out.println(cInv);
}
This is the relevant part of the text file that it reads (or should be reading):
---Phonemes---
Consonants: 43
Vowels: 9
And it's output is 0
I've tried typing 43 at the very beginning of the file, and I've also tried typing the number in the input, but I keep getting 0 nevertheless. Does someone know what I'm missing or doing wrong?
First, change your assignments as you are reassigning the same static variables.
public static void setCInv(int CInv) {Problem.cInv = CInv;}
public static void setVInv(int VInv) {Problem.vInv = CInv;}
Second, you need to move across all tokens in the file to identify the numbers and update the respective variable.
//Gathers the language values from the file.
public static void readFile() throws FileNotFoundException {
takeFile();
scanFile = new Scanner(language);
int num = 0;
scanFile.nextLine(); //Skip ---Phonemes---
setCInv(getInt(scanFile.nextLine()));
setVInv(getInt(scanFile.nextLine()));
}
public static int getInt(String str){
System.out.println(str);
int num =0;
Scanner line = new Scanner(str);
//Splits the scanned line into tokens (accessed via next()) and search for numbers.
//Similar thing could have been done using String.split(token);
while(line.hasNext()){
try{
num = Integer.parseInt(line.next());
return num;
}catch(NumberFormatException e){}
}
return num;
}
I'm struggling with a specific method which takes in a String parameter. The promptString method will print its parameter to the user as a prompt, and then return a String that is the result of reading the console via the nextLine() method. For this program you will use nextLine() exclusively.
I've prompted the user with a question using a parameter, and then used nextLine to read the string but after that I am a bit lost. How can I get the method to print to the console?
import java.util.*;
public class StarWarsName{
public static void main (String [] args) {
promptString("Enter your first name: ");
}
public static String promptString (String n) {
Scanner console = new Scanner(System.in);
String first = console.nextline();
return first.trim();
}
}
I think you are over-thinking this thing. Just print it to the console.
public static void main(String[]args){
String result = promptString("Enter your first name: ");
System.out.println(result);
}
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.
I created a method called readFileAsScanner. It creates a file and a Scanner which attaches to the file. Then returns the Scanner.
Neverthelesss, I use it. The Scanner can be only used once. Why? Can I reset it by the reset() method of Scanner to make it reusable?
import java.io.*;
import java.util.*;
public class Lab10{
public static void main(String[] args)throws FileNotFoundException{
String[] words = readWords();
int i;
for(i=0;i<words.length;i++)
System.out.println(words[i]);
System.out.println(words.length);
}
public static String[] readWords()throws FileNotFoundException{
Scanner data = readFileAsScanner();
String[] words = new String[estimateWords(data)];
int i=0;
while(data.hasNext()){
System.out.println(data.next());
}
return words;
}
public static Scanner readFileAsScanner() throws FileNotFoundException{
Scanner input = new Scanner(System.in);
System.out.println("Input file name:");
//String fileName = input.next();
String fileName = "unsorted.txt";
Scanner data = new Scanner(new File(fileName));
return data;
}
public static int estimateWords(Scanner data){
int estimatedSize = 0;
while(data.hasNext()){
data.next();
estimatedSize++;
}
return estimatedSize;
}
}
You're consuming everything that you want to read in the estimateWords method call. By the time the scanner advances to the end of the file, you've read pretty much everything there is to read in the file, and the scanner's next call to hasNext() will return false.
You can fix this in one of two ways:
Open the file twice with a Scanner instance in each method call and pass in the filename, or
Open the file once, perform both a count and a reading of data in one method only.
I would opt for the latter, since it would be more straightforward and better practice (you typically don't see Scanner instances passed around).
Because the underlying stream is at end, and probably cannot be rewound or reset, and you can't attach a existing Scanner to another stream.
I have only one method main. How to check System.out.println() and replace Scanner to input values automatically using JUnit?
P.S. Please, provide some solutions...
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int[] arr = new int[4];
for (int i = 0; i < arr.length; i++) {
arr[i] = scanner.nextInt();
}
for (int i = 0; i < arr.length; i++) {
int res = 0;
int k = 0;
int num = arr[i];
/*.....*/
System.out.println(num);
}
}
Ideally, extract the awkward dependencies so that you can test without them. Change main to simply:
public static void main(String[] args) {
doWork(new Scanner(System.in), System.out);
}
// TODO: Rename to something meaningful
public static void doWork(Scanner input, PrintStream output) {
// Remainder of code
}
(Consider using a Writer instead of a PrintStream for output.)
Then you don't really need to unit test main - but you can test doWork using a Scanner based on a StringReader, and output based on a StringWriter, providing whatever input you want and checking the output.
I faced a similar issue and this is what I ended up doing.
First off, I'd suggest doing as #Jon-Skeet suggests and instead of using the main(String[]) method of the class, create a separate method.
Then you can have that method take in an InputStream as a parameter and then create a Scanner object within the method that uses the passed InputStream as its source. That way you can pass any InputStream, such as System.in, to the method when it's called (elaboration below).
package my.package;
import ...;
public class MyClass
{
public static void myMethod(InputStream inputStream)
{
Scanner inputScanner = new Scanner(inputStream);
// Do stuff with the Scanner such as...
String input = inputScanner.nextLine();
System.out.println("You inputted " + input);
}
}
Now, in your production source code you can call myMethod and pass it System.in as an argument as such, myMethod(System.in);
And then in your unit tests, you can create mock input values via a ByteArrayInputStream:
package my.package;
import ...;
public class MyClassTest
{
#Test
void testMyMethod()
{
// Simulates a user inputting the string "Mock input" and hitting enter
assertDoesNotThrow(myMethod(new ByteArrayInputStream("Mock input\n".getBytes())));
}
}
And voila, you now have a way to pass your method mock input as well as it being more modular overall.
I just want to point out without getting too much into it, that when working with System.in, one needs to be careful about closing it and in unit tests when working with input streams, one needs to be careful about reusing a reference to the same InputStream as its state can persist across uses.