I'm trying to learn unit testing and Maven, to do so I'm using JUnit and writing simple random name generator. I have following class:
public class Database {
public String readRandomName(String url) throws FileNotFoundException {
int sum = calculateFileLines(url);
int lines = (int) (Math.random()*sum);
File file = new File(url);
Scanner scanner = new Scanner(file);
for (int i=0; i<lines;i++){
scanner.nextLine();
}
return scanner.nextLine();
}
public int calculateFileLines(String url) throws FileNotFoundException {
int sum = 0;
try (Scanner scanner = new Scanner(new File(url))){
while(scanner.hasNextLine() && scanner.nextLine().length()!=0){
++sum;
}
}
return sum;
}
}
When I run simple test like this:
public static void main(String[] args) throws FileNotFoundException {
Database database = new Database();
database.readRandomName("names/maleNamesPL.txt");
}
It works perfectly, but when I tried to write JUnit test with assertion there is an unexpected failure which I don't understand. This is test code:
#Test
public void readRandomNameTest() throws FileNotFoundException {
Database database = new Database();
Assert.assertNotNull("Should be some name", database.readRandomName("names/maleNamesPL.txt"));
}
And the results:
Tests in error:
readRandomNameTest(DatabaseTest): No line found
I would appreciate any help, thank you!
You're calling nextLine() and it's throwing an exception when there's no line, exactly as the javadoc describes. It will never return null
http://download.oracle.com/javase/1,5.0/docs/api/java/util/Scanner.html
With Scanner you need to check if there is a next line with hasNextLine()
so the loop becomes
while(scanner.hasNextLine()){
String str=scanner.nextline();
//...
}
Related
I cannot call this function that handles a text file.
I try to call it but an exception is thrown. I tried various approaches but nothing has worked so far.
public static void spracujSubor () throws IOException {
File f = new File("test.txt");
Scanner sc = new Scanner(f);
try {
while(sc.hasNextLine()) {
String nazov = sc.next();
String model = sc.next();
double cena = sc.nextDouble();
Auto rep = new Auto(nazov, model,cena);
aPozicovna.aAuto.add(rep);
}
} catch(IOException ioe){
System.err.println(ioe);
}
sc.close();
}
First of all, we can't help you figure out what causes the IOException if you don't (at least) show us the exception's message. The complete stacktrace would be ideal, but the message you help a lot.
There are multiple places where the IOException could be thrown, including:
In the new Scanner(f) if the file doesn't exist, isn't readable, has the wrong pathname, and a few other cases.
In the various calls on the Scanner object in the loop, depending on your file syntax.
In the close() call ... in theory.
Some of these are inside the try-catch. Others are before or after it. For the cases inside the try catch, you are catching the exception, printing a message, and then proceeding as if nothing happened. That is bad. Here is a better structure ... that doesn't squash the exceptions.
public static void spracujSubor () throws IOException {
File f = new File("test.txt");
try (Scanner sc = new Scanner(f)) {
while(sc.hasNextLine()) {
String nazov = sc.next();
String model = sc.next();
double cena = sc.nextDouble();
Auto rep = new Auto(nazov, model,cena);
aPozicovna.aAuto.add(rep);
}
}
}
Note that since the Scanner is an Autocloseable, it will be closed automatically when you exit the try-with-resources.
public static void main(String[] args) throws FileNotFoundException {
Scanner sc = new Scanner(new FileReader(args[1]));
String co = sc.next();
coup = Integer.parseInt(co);
I get a FileNotFoundException when I try to pass an int into the second argument in command line. This is only part of the code, a text file is passed as args[0]. However, I can't figure out how to pass a simple integer, only text files.
public static void main(String[] args) throws Exception
{
Scanner scan = new Scanner(new FileReader(args[0]));
int integerFromCM = Integer.parseInt(args[1]);
}
You state that a text file is the first argument (args[0]) so assign that in the scanner and when grabbing the integer all you need to do is send args[1] into Integer.parseInt method. You are getting the exception because you are assigning a FileReader object with the file name of the integer passed in.
You can't pass an int, but you can parse one:
public static void main(String[] args) {
String filename = args[0];
int i = Integer.parseInt(args[1]);
// ...
}
If you are getting a FileNotFoundException, one easy way to debug it is:
File file = new File(filename);
System.out.println(file.getAbsolutePath());
and it will be obvious where the problem lies, which is almost always the current directory of the application is not what you think it is.
Reviewing your code it reads as follows:
Create a Scanner to read the file in the first command line argument
Get the first integer from that Scanner as a String
Parse that String to an int
It is clearly sequenced to require a file from the first argument and that looks like it is intended.
Create a file called number.txt:
42
NumberPrinter.java:
import java.io.Scanner;
import java.io.FileReader;
public final class NumberPrinter {
public static void main(String[] args) throws Exception {
Scanner scanner = new Scanner(new FileReader(args[1]));
String numberInFile = scanner.next();
int number = Integer.parseInt(numberInFile);
System.out.println(number);
}
}
Run as follows:
java NumberPrinter number.txt
And it will print:
42
Alternatively if you intend to parse an int directly from the command line parameters try:
public final class NumberPrinterDirect {
public static void main(String[] args) throws Exception {
int number = Integer.parseInt(args[0]);
System.out.println(number);
}
}
NumberOrFilenameAwkward.java:
import java.io.Scanner;
import java.io.FileReader;
public final class NumberOrFilenameAwkward {
public static void main(String[] args) throws Exception {
int number;
try {
number = Integer.parseInt(args[0]);
} catch (NumberFormatException thisIsVeryUgly) {
Scanner scanner = new Scanner(new FileReader(args[1]));
String numberInFile = scanner.next();
number = Integer.parseInt(numberInFile);
}
System.out.println(number);
}
}
That is a terrible solution and screams for using a command line parsing library like JewelCLI or commons-cli to solve it cleanly.
I'm writing a java program that I'm running on the CMD line that copies several .txt files into one. For example I have three .txt files that I created. Chapter1.txt, chapter2.txt Chapter3.txt. All the contents of these files needs to be copied to book.txt. I ran the code and it ran fine until I entered the command.
java CatFiles chapter1.txt chapter2.txt chapter3.txt book.txt
The book.txt file is created but only the contents of one file are copied and I get this error code
java.land.illeglStateException: Scanner
at java.util.Scanner.ensureOpen(unknown Source)
at java.util.Scanner.findWithinHorizon(unknown Source)
at java.util.Scanner.hasNextLine(unknown Source)
at CatFiles.main(CatFiles.java)
Here's my code
public class CatFiles {
public static void main(String[] args) throws IOException {
if (args.length < 2) {
System.out.println("Usage: CatFiles sourcefile1 sourcefile2 . . . targetfile");
return;
}
String target = args[args.length - 1];
FileReader reader = null;
PrintWriter out = new PrintWriter(target);
for (int i = 0; i < args.length - 1; i++) {
String source = args[i];
reader = new FileReader(source);
}
Scanner in = new Scanner(reader);
while ( in .hasNextLine()) {
try {
String line = in .nextLine();
out.println(line);
} finally { in .close();
out.close();
}
}
}
}
Use this (note: checks about arguments are left as an exercise):
public static void main(final String... args)
{
final List<String> list = new ArrayList<>();
Collections.addAll(list, args);
final Path dstFile = Paths.get(list.remove(list.size() - 1));
try (
final OutputStream out = Files.newOutputStream(dstFile);
) {
for (final String s: list)
Files.copy(Paths.get(s), out);
}
}
You should put the while loop inside of the try block and not the contrary. Otherwise you're closing the Scanner at the first loop and you can not use it anymore. Close your Scanner once you're never using it again.
I honestly think correct indentation would have helped here.
JavaDoc
Throws: NoSuchElementException if no line was found
java.lang.IllegalStateException if this scanner is closed
Solution
Scanner in = new Scanner(reader);
try{
while (in.hasNextLine()) {
String line = in.nextLine();
out.println(line);
}
} finally {
in.close();
out.close();
}
Idiomatic Solution using Guava:
This includes basic error checking on valid number of arguments. This does not do robust idiomatic exception handling for brevity and scope control.
This solution also uses Immutable data throughout making it immune to logic errors because of side effects and state mutation.
Q33846584.java
Import statements are available in the link above.
public class Q33846584
{
public static void main(final String[] args) throws Exception
{
checkArgument(args.length > 2, "You must supply at least 3 file paths as arguments dest, src, src, ...");
final List<Path> paths = Lists.transform(Arrays.asList(args), new Function<String, Path>()
{
#Nullable #Override public Path apply(#Nullable String input)
{
return Paths.get(checkNotNull(input));
}
});
final Path destination = paths.get(0);
try (final OutputStream fos = new FileOutputStream(destination.toFile()))
{
for (final Path p : paths.subList(1, paths.size()))
{
if (p.toFile().exists())
{
System.out.format("Reading %s and writing to %s", p.toAbsolutePath(), destination.toAbsolutePath());
final FileInputStream fis = new FileInputStream(p.toFile());
ByteStreams.copy(fis, fos);
System.out.println();
}
else
{
System.err.format("%s does not exist skipping!", p.toAbsolutePath());
System.err.println();
}
}
}
}
}
Without Guava:
You would have to implement the transformation of the String[] yourself in a imperative loop which is straightforward.
You would have to implement copying the InputStream to the OutputStream which is well documented on the internet in general but is basically boilerplate code. You will end up with a possibly buggy or inefficient version of what Guava does. It would only be useful as a learning exercise at best.
Both of these activities are easy to find on Stackoverflow and are left as exercises for the reader.
I am trying to create a junit test on a method that calls for a user input using scanner and System.in.
The method being tested looks like this:
public void setUserAnswer(){
Scanner input = new Scanner(System.in);
userAnswer = input.nextInt();
}
Currently, I am using the following set up in jUnit:
StringBuilder sb = new StringBuilder();
sb.append("");
sb.append((problem.getOperand1()+problem.getOperand2()));
String data = sb.toString();
System.setIn(new ByteArrayInputStream(data.getBytes()));
operand1 and operand2 are random generated numbers which the user adds and enters the answer for.
The problem I have is the System.setIn doesn't pass from the jUnit class to the class being tested.
Help?
To cut the discussion, your method could be tested in following way:
public class MathProblem {
private int userAnswer;
public void setUserAnswer(){
Scanner input = new Scanner(System.in);
userAnswer = input.nextInt();
}
public int getUserAnswer() {
return userAnswer;
}
}
and now the Test:
public class MathProblemTest {
private MathProblem mathProblem;
#Before
public void before() throws Exception {
mathProblem = new MathProblem();
}
#Test
public void testGetUserAnswer() throws Exception {
StringBuilder sb = new StringBuilder();
sb.append("41 20");
String data = sb.toString();
System.setIn(new ByteArrayInputStream(data.getBytes()));
mathProblem.setUserAnswer();
assertThat(mathProblem.getUserAnswer(), equalTo(41));
}
}
As the others already mention: This code behaves as expected.
So if you do not see a correct behaviour the test might be broken or the problem is in another region of your code, that you have not posted. So ask your self: Where does your example differ from this example?
You should not be messing with System.in during a unit test.
Ask yourself what it is you're testing. Are you testing the Scanner code, or the code that uses whatever values are entered by the user?
Your code probably does 3 things:
Ask user for input
Perform operation
Display result
In a unit test, you're testing the operation, not the user prompting or the display logic. Or if you do, they should be 3 different unit tests, and remember that if you're testing the user prompting, you're testing the use of the Scanner, not whether the Scanner can read System.in.
So, first split your code to:
public class MyClass {
public static void main(String[] args) {
Input input = promptUserForInput(new Scanner(System.in), System.out);
Result result = performOperation(input);
printResult(System.out, result);
}
// methods here
}
You don't have to create new classes for Input and Result if they are simple values. They could also be the same class, e.g. an instance of MyClass.
This way you can test if the operation works for various inputs, which is your primary concern.
#Test
public void testOperation1() {
Input input = new Input(5, 15, true); // true means subtract
Result result = MyClass.performOperation(input);
assertEquals(-10, result.getValue());
}
#Test
public void testOperation2() {
Input input = new Input(5, 15, false); // false means add
Result result = MyClass.performOperation(input);
assertEquals(20, result.getValue());
}
You can also test user prompting and result printing, if needed.
#Test
public void testPrompt() {
String userInput = "5 15\nYes";
PrintStream out = new PrintStream(new ByteArrayOutputStream());
Input input = MyClass.promptUserForInput(new Scanner(userInput), out);
assertEquals(5, input.getNum1());
assertEquals(15, input.getNum2());
assertTrue(input.isSubtractRequested());
}
#Test
public void testPrint() {
ByteArrayOutputStream buf = new ByteArrayOutputStream();
try (PrintStream out = new PrintStream(buf)) {
MyClass.printResult(out, new Result(-10));
}
String outText = new String(buf.toByteArray());
assertEquals("Result is -10\r\n", outText);
}
I'm tasked, by my professor, to write a program to read a .csv file (778 rows (including header row), 8 columns).
I need to:
1. Write a method to receive the name of the file as its argument and then print the number of lines in the file.
public void printNumberOfLinesInFile(String fileName)
Write a method to receive the name of the file as its argument and then print the number of private and non-private colleges.
public void printNumberOfPrivateNonPrivateCollegesInFile(String fileName)
Write a method to receive the name of the file as its argument and then print the private college name with largest out of state tuition.
public void printMostExpensivePrivateCollegeInFile(String fileName)
Write a method to receive the name of the file as its argument and then print the non-private college with largest out of state tuition.
public void printMostExpensiveNonPrivateCollegeInFile(String fileName)
Write a method to receive the name of the file as its argument and then print the number of applications and the number of applicants that are accepted for private and non-private colleges.
public void printNumberOfApplications(String fileName)
Write a method to receive the name of the file as its argument and then print following information for private and non-private colleges.
Average of expenses for books.
Average of expenses for room.
Average of personal expenses.
public void printAverageOfExpenses(String fileName)
Disclaimer: I do not want anyone to do my homework for me. I need to learn so I can apply my knowledge when I graduate and enter industry. I'm simply asking for a hint or a better way at writing the code.
My code thus far:
public class Week14
{
public String data;
public void printNumberOfLinesInFile(String inFile) throws IOException
{
int collegeCount = 0;
FileReader fileRead = new FileReader(inFile);
BufferedReader bufferRead = new BufferedReader(fileRead);
while(true)
{
String line = bufferRead.readLine();
if(line == null)
{
break;
}
collegeCount++;
//System.out.println(line);
}
System.out.println(collegeCount-1 + " Colleges total.");
}
public void printNumberOfPrivateNonPrivateCollegesInFile(String inFile) throws IOException
{
int privateCount = 0;
int nonprivateCount = 0;
int count = 0;
FileReader fileRead = new FileReader(inFile);
BufferedReader bufferRead = new BufferedReader(fileRead);
while((data = bufferRead.readLine())!= null)
{
String line = bufferRead.readLine();
String [] lineItems = line.split(",");
for(int i = 0; i < line.length(); i++)
{
if(lineItems[i].equals("Yes"))
{
privateCount++;
}
}
break;
}
System.out.println(privateCount+" private Colleges.");
System.out.println(nonprivateCount+ " non-private Colleges.");
}
public void printMostExpensivePrivateCollegeInFile(String inFile) throws FileNotFoundException, IOException
{
int mostExpensive = 0;
int currentExpensive = 0;
FileReader fileRead = new FileReader(inFile);
BufferedReader bufferRead = new BufferedReader(fileRead);
while((data = bufferRead.readLine())!= null)
{
String line = bufferRead.readLine();
if(line.equals("OutstateTuition"))
{
System.out.println(line);
}
else
{
System.out.println(line);
}
}
}
public void printMostExpensiveNonPrivateCollegeInFile(String fileName)
{
}
public void printNumberOfApplications(String fileName)
{
}
public void printAverageOfExpenses(String fileName)
{
}
public static void main(String[] args) throws FileNotFoundException, IOException
{
File inFile = new File("College.csv");
FileReader fileReader = new FileReader(inFile);
BufferedReader buffReader = new BufferedReader(fileReader);
Week14 w1 = new Week14();
//w1.printNumberOfLinesInFile("College.csv");
w1.printNumberOfPrivateNonPrivateCollegesInFile("College.csv");
//^^^The above line goes into an infinite loop^^^
//w1.printMostExpensivePrivateCollegeInFile("College.csv");
}
}
The problem is, I'm stuck on trying to count the amount of private and nonprivate colleges. In my method, printNumberOfPrivateNonPrivateCollegesInFile (line 39), I'm running into an exception: java.lang.ArrayIndexOutOfBoundsException: 8
I've asked my professor how I can avoid this, I've looked online and the problem seems to lie with the iterator int 'i'. I'm trying to traverse the array, and 'i' is out of bounds. When I put a '1' in
if(lineItems[i].equals("Yes"))
for my privateCount, there is an output of 67 from privateCount, (I think it is counting the individual characters for some reason).
My question, what would be the most effective way to traverse the entire .csv file, and to access individual columns so I can count them and output them?
Any help would be greatly appreciated.
edit:
I have changed the while loop:
while(true)
{
String line = bufferRead.readLine();
String [] lineItems = line.split(",");
if(line == null)
{
break;
}
for (String lineItem : lineItems) {
privateCount++;
}
}
Now I can traverse the entire .csv file, but I'm receiving a java.lang.NullPointerException when I try and count.
edit 2:
I've redone my while loop again,
while(true)
{
String line = bufferRead.readLine();
String [] lineItems = line.split(",");
for (String lineItem : lineItems) {
if (lineItem.equals("Yes")) {
privateCount++;
}
}
System.out.println(privateCount);
}
I'm now counting the right value for privateCount, but there's a NullPointerException at :
String [] lineItems = line.split(",");
and the loop will not let me put my 'echo' outside of the while-loop without a 'break' statement.
With respect to actual industry-level code, and assuming that assignment did not specifically focus on actual CSV decoding, I would recommend finding and using a library to handle low-level decoding, such as OpenCSV, SuperCSV or CSV-module for Jackson.
This way your code can focus on more interesting part of finding specific values, and not on intricate details like possible escaping and/or quoting of contents.
If the focus is on CSV edge cases this is not the approach to use; but for real production code one hopefully rarely if ever writes the actual low-level decoding part, given the existence of multiple good libraries for the task.
if(lineItems != null && lineItems.length>0){
// do your loop
}
if (lineItem!= null && !lineItem.trim().equals("") && lineItem.equals("Yes")) {
privateCount++;
}
most likely will prevent your null issue
public void printNumberOfPrivateNonPrivateCollegesInFile(String inFile) throws IOException
{
int privateCount = 0;
int nonprivateCount = 0;
FileReader fileRead = new FileReader(inFile);
BufferedReader bufferRead = new BufferedReader(fileRead);
try
{
while(true)
{
String line = bufferRead.readLine();
String [] lineItems = line.split(",");
//System.out.println(Arrays.toString(lineItems));
for (String lineItem : lineItems)
{
if (lineItem!= null && !lineItem.trim().isEmpty() && lineItem.equals("No"))
{
nonprivateCount++;
}
if (lineItem!= null && !lineItem.trim().isEmpty() && lineItem.equals("Yes"))
{
privateCount++;
}
}
//System.out.println(privateCount);
}
}
catch(NullPointerException npe)
{
}
System.out.println(privateCount);
System.out.println(nonprivateCount);
}
Fixed it. I'm now just catching the exception so it isn't as annoying. Thanks all for the help.