To test the main method, I decided to call it with an array of Strings. Is it the most optimal way?
There is no other way. How could you test a method expecting an array of strings without calling it and passing it an array of strings? That said, the main method should be very, very small, and delegate to other methods to make things easier. Something like
public static void main(String[] args) throws IOException {
new Program(new FileInputStream(args[0]),
new FileOuptutStream(args[1]),
System.out)
.run();
}
That way, what you need to really test is the run()
method of Program
(and the other classes and methods it might use).
how can I read that from the console to assert that the expected output has been printed?
See how, in the main method above, I pass System.out to the program? That's where the program should write to, instead of writing to System.out
directly.
Since you can create a Program
in your test and pass it any PrintStream, you can choose to pass a PrintStream that simply prints to an in-memory data structure, instead of passing System.out
. For example: new PrintStream(someByteArrayOutputStream)
, and then check what the content of the byte array is.
Or, instead of passing a PrintStream
to the Program
constructor, you could define a higher-level abstraction like
public interface Output {
public void println(String s);
}
This would allow to pass any mock implementation in your test, and, i your main method, to pass one that actually prints to System.out
:
new Program(..., System.out::println)
Sometimes, I'm expecting an exception to be caught
Then test that it's doing/returning the right thing when an exception is being thrown. Let's take an example:
/**
* Parses the given string as an Instant, and returns null if not parseable
*/
public Instant parse(String s) {
try {
return Instant.parse(s);
}
catch (DateTimeParseException e) {
return null;
}
}
You can simply test this method by first passing a valid String, and check that the method returns the right Instant, and then by passing an invalid String, and checking that the method returns null.