Home > other >  How to write a junit test for a scanner? (Reading a file)
How to write a junit test for a scanner? (Reading a file)

Time:09-22

I have a method that scans a file and assigns values to an object:

private List<Customer> customerList = new ArrayList<Customer>();

public void scanLocalFile() throws FileNotFoundException {
  File file = new File("input.txt");
  Scanner scan = new Scanner(file);
  while (scan.hasNextLine()) {
      String[] fields = line.split(";");
      String name = fields[0];
      String score = fields[1];

  Customer customer = new Customer(name, score);
  customerList.add(customer);
  }
scan.close();
}

How do I write a junit test for a method like this? Is it possible to use the same file ("input.txt") for a unit test as well?

The file's structure:

John Smith;45;
Adam West;78;

CodePudding user response:

The basic approach to make this code unit-testable is to not hard-code the use of the input.txt file.

Stultuske suggests passing in the File as a parameter to the method, in order that you can then run the method for an arbitrary file during testing.

I'd go a step further than that and say: pass in a Reader. Scanner has a constructor which accepts a Reader, and then you don't have to mess around with files during you unit test.

For example, you can construct a StringReader with a hard-coded string that is the "file contents".

StringReader sr = new StringReader("John Smith;45;\nAdam West;78;");

Note, however, that if you pass in a Reader, you shouldn't close the Scanner at the end, because that will close the Reader; and it is bad practice for code to close a Reader (or Writer or Input/OutputStream; generally any resource) that it didn't open.

public void scanLocalFile(Reader r) {
  Scanner scan = new Scanner(r);
  while (scan.hasNextLine()) {
     // ...
  }
}

Actually, since you're just reading lines from the Scanner, I think it would be better to use BufferedReader instead:

public void scanLocalFile(Reader r) {
  new BufferedReader(r).lines()
      .map(line -> {
        String[] fields = line.split(";");
        return new Customer(fields[0], fields[1]);
      })
      .forEach(customerList::add);
}
  • Related