简体   繁体   中英

Java - How to unit test main method dependencies?

What is the proper way to unit test the main method here? Ideally, I just want to verify that an (mock) instance of SomeProgram invoked the run() method inside the main method. I know I can create a setter to set the instance of SomeProgram, but it seems like a code smell since it doesn't do anything other than enable easier testing? Same with the public accessor on the run() method. It is liberal for the purpose of testing. How can I test it if it was private? I'm looking for changes to the class, maybe apply some design patterns that would alleviate this problem.

public class SomeProgram {

    public void run(Dependency1 dependency1, Dependency2 dependency2) {
        dependency1.doSomething();
        dependency2.doSomething();
    }

    public static void main(String[] args) {
        new SomeProgram().run(new Dependency1(), new Dependency2());
    }
}

There's no useful way to unit test a main method. Typically, these methods initialise an object graph (or explicitly call into a DI container like Spring or Guice to do so) and so you end up not having any really useful test seams in which to directly inject mocks or fakes.

What you can do is to use integration tests. You can set up your integration environment and configure the main method to point to things which are under your tests control. So, for example, if your program talks to a database, then your test can spin up an embedded database and use command line parameters to point the program at the embedded database rather than an external database. You can similarly fake out external Rest APIs using embedded Jetty.

But it's important to accept that these would not be unit tests. They'd be integration tests, and would have the problems you generally associate with integration tests - they're slower than unit tests and you have less control over the system and so testing some things can be tricky.

Test the functionality of the Program, not the Program itself.

You can do this by utilizing dependency injection. This works best if Dependency1 is an interface instead of a concrete class.

public class SomeProgram 
{
    private final Dependency1 _dependency1;
    private final Dependency2 _dependency2;

    public SomeProgram(Dependency1 dependency1, Dependency2 dependency2)
    {
        _dependency1 = dependency1;
        _dependency2 = dependency2;
    }

    public void run() 
    {
        dependency1.doSomething();
        dependency2.doSomething();
    }
}

Then your main method will be precisely like the unit test, except that it will inject real dependencies.

public static void main(String[] args) 
{
    new SomeProgram(new Dependency1(), new Dependency2()).run();
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM