2

Is it worth trying to unit test a main method of a console application?

The main method is the only code that doesn't have test coverage right now.

public static void main(String[] args) { if (args.length != 2) { System.out.println("Pass the root directory and the directory to scan."); System.exit(1); } Path root = Paths.get(args[0]); Path scan = Paths.get(args[1]); Demo demo = new Demo(); String output = demo.scan(root, scan); System.out.println(output); } 
2
  • 2
    Without any ability to mock dependencies (particularly the results of Demo#scan(Path, Path), this code just isn't that testable. The most meaningful unit test here (in my opinion) would be just to verify unhappy behavior (wrong # of args, maybe nonexistant paths). Otherwise you're really just testing your entire application. Commented Feb 19, 2017 at 4:15
  • @CollinD OP can use PowerMockito to mock the Demo class. Commented Feb 19, 2017 at 22:19

2 Answers 2

6

What are you testing, really? This is the question you have to ask yourself when deciding to test certain pieces of code.

In an ideal world, having 100% code and branch coverage is nice, and having the ability to ensure that code is functional when rewritten is a huge benefit. However, one should never use code coverage alone as a suitable "happy" metric for test coverage.

In this case, you have to look long and hard at what you really want to inspect here. Given that you're newing up a lot of things, and that you'll have to mock out almost everything here, the realistic thing you can do is test the mechanical process of, "Does this object call this method with these parameters?" Frankly, that doesn't feel like a good test.

I would recommend that you exclusively test Demo#scan instead of the entirety of main, because:

  • scan is a method that requires a new instance of Demo, which is not easily injected into main. Yes, I'm aware you can use PowerMockito to accomplish this, but mocking out something that's newed up is a test smell to me.
  • Your application will fail to run if any of these are true:
    • args doesn't receive the right number of params
    • The path passed in through args is invalid or malformed
  • If you did go down the path of testing this, you'd start to realize that you're really testing a lot of library code and ensuring that the library code worked. That has some advantages, but in this case, the juice isn't worth the squeeze.
Sign up to request clarification or add additional context in comments.

Comments

1

A main method is still code which can contain bugs and causing undesired application behavior. So, testing a main method can make sense in the same way testing every other method does.

Unfortunately, a main method is a static method which makes unit testing without additional frameworks not possible. At best your main method should contain one method call then you don't have to worry if you should test it or not.

Anyway, in my opinion the following tests can be derived from your main method.

  • Does the program terminates if the path and/or scan directory is not provided?
  • Is the result printed to the console?
  • etc.

Sure, it's comprehensible to say that the test results are very obvious and I it needs just one look at the code to say it works or the program will fail. On the other hand what if of other developers which are not that well skilled change your code or some requirement changes and you will have additional arguments to process. Would it be still that easy?

And finally, in a pure TDD process you already had defined similar test cases which have to be covered before you have written your main method at all.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.