0

I have a question regarding JUnit.

I have a java program that runs from command line. it accepts as an input the name of two txt files (String args[]) and then it process the data in the first file and output the result to the second.

I'm now in a stage of writing test-cases for my program. I decided to use JUnit framework.

My questions are:

  1. To test the main method, I decided to call it with an array of Strings. Is it the most optimal way?
  2. Now, I want to test the other functions, the majority of them are printing specific outputs, how can I read that from the console to assert that the expected output has been printed?
  3. Sometimes, I'm expecting an exception to be caught. And since it's been caught I can't use @Test (expected Exception.class). is there another way to check if the exception has been thrown and caught at the same time?

Sorry for my long list of questions!

Thanks.

Alice J
  • 59
  • 1
  • 7
  • It seems like you are testing too many things at once. A test should test one thing, and one thing only. If you compute something and then print it, separate pieces of code should probably be used for that. Also you should test external behaviour of your code, and checking if something happened inside your code should probably not be tested. unless it has some kind of effect on the state of the program (in which case you should test this state). Also see: https://stackoverflow.com/questions/1119385/junit-test-for-system-out-println – mszymborski Mar 30 '18 at 14:35

3 Answers3

0

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.

JB Nizet
  • 678,734
  • 91
  • 1,224
  • 1,255
0

I suggest using some unit testing framework. Mockito can be a good place to start. http://site.mockito.org/ There you can mock you FileReaders and Writers. You can also expect certain method to be called with your parameters and more.

Shanu Gupta
  • 3,699
  • 2
  • 19
  • 29
0

Unit test is instantiates a small portion of our application and verifies its behavior independently from other parts. This, however, requires that your code is organized so that you actually can instantiate a small portion of our application and verify its behavior independently from other parts.

Now, to your questions:

  1. Yes, it is fine. Call your main method with an array of strings and check that it calls whatever it is supposed to call.

  2. There are many ways to do this. For example, instead of printing to System.out or similar you should set or pass a writer or a print stream which will be then used for output. Then, in the test you could instantiate and pass a test-owned writer. You functions will happily output to this writer and finally you can check the contents of the writer to verify what's written.

  3. If you can provike throwing an exception via arguments, there's no problem. Just check that the method does the right thing in this situation. If forcing an exception is not easy, extract the possibly-exception-throwing part into a separate method. You can then mock your object and force throwing an exception from that method.

lexicore
  • 42,748
  • 17
  • 132
  • 221