通过 junit 测试主要方法

新手上路,请多包涵

我写了一个类,它从控制台获取输入并在 main 方法中获取参数。 main 方法为不同的控制台输入调用不同的方法,并为不同的参数调用不同的函数。所以我想通过模拟文件中的这些输入来用 Junit 测试这个主要方法。我该怎么做? junit中有没有特殊规定测试类的main方法?

原文由 user2719152 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 992
2 个回答

要提供来自文件的输入,请创建 FileInputStream 并将其设置为 System.in 流。您可能希望在 main 方法完成后将原始设置恢复原状,以确保以后使用它的任何东西仍然有效(其他测试,JUnit 本身……)

这是一个例子:

 @Test
public void testMain() throws IOException {
    System.out.println("main");
    String[] args = null;
    final InputStream original = System.in;
    final FileInputStream fips = new FileInputStream(new File("[path_to_file]"));
    System.setIn(fips);
    Main.main(args);
    System.setIn(original);
}

在您的实际代码中,您将希望处理任何 IOExceptions 并使用比文件的完整路径更好的东西(通过类加载器获取它),但这给了您一般的想法。


编辑:

几年后有了更多的智慧,我不得不同意 Michael Lloyd Lee mlk 的回答,认为这是更好的方法,如果可能的话应该首选什么。在包含您的 main 方法(或什至是一个单独的类)的类中,应该有一个接受任意 InputStream 和参数数组的方法。它可以是一个静态方法。 main 方法然后使用 System.in 流作为参数调用它。

 public class Main {
    public static void main(String[] args) {
        start(System.in, args);
    }
    public static void start(InputStream input, String[] args) {
        // use input and args
    }
}

或者,您可以使用一个带有接受参数数组的构造函数的类来创建一个正确配置的实例,然后在其上调用一个接受 InputStream 的实例方法,如下所示:

 public class Main {
    public static void main(String[] args) {
        Bootstrapper bootstrapper = new Bootstrapper(args);
        bootstrapper.start(System.in);
    }
}

public class Bootstrapper { // just some name, could be anything else

    // could have some instance fields here...

    public Bootstrapper(String[] args) {
        // use the args to configure this instance, set fields, get resources...
    }

    public void start(InputStream input) {
        // use input
    }
}

最适合要求和程序设计的。在这两种情况下,您最终都会得到一些可以使用从文件中获得的 InputStream 进行单元测试的东西。对 Main.start 执行简单静态方法调用的测试,或创建 Bootstrapper 实例然后调用其 start 方法的测试。现在您的测试不再依赖于 System.in 流。 main 方法做的工作很少,而且非常简单,您无需单独测试即可相信它的正确性。在某些时候,一段代码变得如此微不足道,以至于测试它等同于不信任编译器。这些主要方法中的问题很快就会变得明显,因为它是您知道将始终被调用的一种方法。一个 main 方法做的太多或者太复杂通常表明代码缺乏模块化。

我保留原来的答案是因为它确实提供了一个解决方案,以防您真的无法通过使用 System.in 并测试 main 方法。这就是我一开始写它的原因,因为我不能确定提问者的限制。有时有人只是想直接回答他们的确切问题,因为没有更好的方法;您不允许更改代码,或者重构它需要付出太多努力并且没有预算,或者使用了一些硬编码为使用系统流等的库。请注意,原始答案无论如何都不那么可靠。如果测试并行而不是顺序运行,换出系统流可能会导致意外和不一致的故障。

原文由 G_H 发布,翻译遵循 CC BY-SA 4.0 许可协议

IMO 测试 main 方法的最佳方法是让 main 方法除了设置世界并启动它之外什么都不做。这样,一个简单的集成测试就可以给出“世界是否已经建立”的答案。

然后所有其他问题变得更容易回答。

main 方法为不同的控制台输入调用不同的方法,并为不同的参数调用不同的函数。

它不应该,它应该调用 someService.somemethod(args) 。该服务像其他任何服务一样接受测试。

所以我想通过模拟文件中的这些输入来用 Junit 测试这个主要方法。我该怎么做?

注入某种形式的伪造品或使用 TemporaryFolder JUnit 规则。

原文由 Michael Lloyd Lee mlk 发布,翻译遵循 CC BY-SA 3.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题