简体   繁体   English

Java-如何对主要方法依赖项进行单元测试?

[英]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. 理想情况下,我只想验证SomeProgram的(模拟)实例在main方法内部调用了run()方法。 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? 我知道我可以创建一个setter来设置SomeProgram的实例,但是它看起来像是一种代码气味,因为它除了启用更容易的测试之外没有做任何其他事情? Same with the public accessor on the run() method. 与run()方法上的公共访问器相同。 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. 没有对main方法进行单元测试的有用方法。 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. 通常,这些方法会初始化对象图(或显式调用诸如Spring或Guice这样的DI容器来这样做),因此您最终没有任何真正有用的测试接缝可以直接注入模拟或伪造品。

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. 您可以设置集成环境并配置main方法以指向受测试控制的对象。 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. 您可以使用嵌入式Jetty类似地伪造外部Rest API。

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. 如果Dependency1是接口而不是具体的类,则此方法效果最好。

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();
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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