如何从我的java应用程序中运行JUnit测试?

时间:2022-12-22 17:20:45

Is it possible to run JUnit tests from inside my java application?

是否可以从我的java应用程序中运行JUnit测试?

Are there test frameworks I can use (such as JUnit.jar?), or am I force to find the test files, invoke the methods and track the exceptions myself?

是否有我可以使用的测试框架(例如JUnit.jar?),还是我强制查找测试文件,调用方法并自己跟踪异常?

The reason why I am asking is my application requires a lot of work to start launch (lots of dependencies and configurations, etc) and using an external testing tool (like JUnit Ant task) would require a lot of work to set up.

我之所以要问的是我的应用程序需要大量的工作来启动启动(许多依赖项和配置等),并且使用外部测试工具(如JUnit Ant任务)需要大量的工作来设置。

It is easier to start the application and then inside the application run my tests.

启动应用程序更容易,然后在应用程序内运行我的测试。

Is there an easy test framework that runs tests and output results from inside a java application or am I forced to write my own framework?

是否有一个简单的测试框架,可以在java应用程序中运行测试和输出结果,还是我*编写自己的框架?

6 个解决方案

#1


78  

Yes, you can. I was doing it couple of times to run diagnostic/smoke tests in production systems. This is a snippet of key part of the code invoking JUnit:

是的你可以。我正在做几次在生产系统中运行诊断/烟雾测试。这是调用JUnit的代码的关键部分的片段:

JUnitCore junit = new JUnitCore();
Result result = junit.run(testClasses);

DON'T use JUnit.main inside your application, it invokes System.exit after tests are finished and thus it may stop JVM process.

不要在应用程序中使用JUnit.main,它会在测试完成后调用System.exit,因此可能会停止JVM进程。

You may want to capture JUnit's "regular" console output (the dots and simple report). This can be easily done by registering TextListener (this class provides this simple report).

您可能想要捕获JUnit的“常规”控制台输出(点和简单报告)。这可以通过注册TextListener轻松完成(此类提供了这个简单的报告)。

Please also be aware of several complications using this kind of method:

请注意使用这种方法的几种并发症:

  1. Testing of any "test framework", including so small one, although is quite simple may be confusing. For example if you want to test if your "test framework" return failure result when one of the tests fails you could (should?) create sample JUnit test that always fails and execute that test with the "test framework". In this case failing test case is actually test data and shouldn't be executed as "normal" JUnit. For an example of such tests you can refer to JUnit's internal test cases.

    测试任何“测试框架”,包括如此小的测试框架,虽然很简单,但可能会令人困惑。例如,如果您想测试当其中一个测试失败时您的“测试框架”是否返回失败结果,您可以(应该?)创建始终失败的示例JUnit测试并使用“测试框架”执行该测试。在这种情况下,失败的测试用例实际上是测试数据,不应该作为“正常”JUnit执行。有关此类测试的示例,您可以参考JUnit的内部测试用例。

  2. If you want to prepare / display your custom report you should rather register your own RunListener, because Result returned by JUnit doesn't contain (directly) information about passed tests and test method (it is only "hardcoded" as a part of test Description).

    如果要准备/显示自定义报告,则应该注册自己的RunListener,因为JUnit返回的结果不包含(直接)有关传递的测试和测试方法的信息(它仅作为测试的一部分“硬编码” )。

#2


11  

As documented in the JUnit FAQ:

如JUnit FAQ中所述:

public static void main(String args[]) {
  org.junit.runner.JUnitCore.main("junitfaq.SimpleTest");
}

#3


10  

The reason why I am asking is my application requires a lot of work to start launch (lots of dependencies and configurations, etc) and using an external testing tool (like JUnit Ant task) would require a lot of work to set up.

我之所以要问的是我的应用程序需要大量的工作来启动启动(许多依赖项和配置等),并且使用外部测试工具(如JUnit Ant任务)需要大量的工作来设置。

You need to remove these dependencies from the code you are testing. The dependencies and configurations are precisely what you are trying to avoid when writing a test framework. For each test, you should be targeting the smallest testable part of an application.

您需要从正在测试的代码中删除这些依赖项。依赖关系和配置正是您在编写测试框架时要避免的。对于每个测试,您应该定位应用程序中最小的可测试部分。

For example, if you require a database connection to execute some process in a class you are trying to test - decouple the database handling object from your class, pass it in via a constructor or setter method, and in your test use a tool like JMock (or write a stub class) to build a fake database handling object. This way you are making sure the tests are not dependent on a particular database configuration, and you are only testing the small portion of code you are interested in, not the entire database handling layer as well.

例如,如果您需要数据库连接来执行您尝试测试的类中的某个进程 - 将数据库处理对象与类分离,通过构造函数或setter方法传递它,并在测试中使用像JMock这样的工具(或编写存根类)来构建虚假的数据库处理对象。这样,您可以确保测试不依赖于特定的数据库配置,并且您只测试您感兴趣的一小部分代码,而不是整个数据库处理层。

It might seem like a lot of work at first, but this kind of refactoring is exactly what your test framework should be fleshing out. You might find it useful to get a book on software testing as a reference for decoupling your dependencies. It will pay off a lot more than trying to bootstrap JUnit from inside your running application.

一开始看起来似乎很多工作,但这种重构正是你的测试框架应该充实的东西。您可能会发现将软件测试的书作为解耦依赖关系的参考是有用的。与尝试从正在运行的应用程序中引导JUnit相比,它将获得更多回报。

#4


2  

According to the JUnit API, JUnitCore has several methods to execute tests inside Java.

根据JUnit API,JUnitCore有几种在Java中执行测试的方法。

Thanks to Tomislav Nakic-Alfirevic for pointing it out.

感谢Tomislav Nakic-Alfirevic指出它。

http://junit.sourceforge.net/javadoc/org/junit/runner/JUnitCore.html

http://junit.sourceforge.net/javadoc/org/junit/runner/JUnitCore.html

#5


2  

In JUnit 5 you can use Launcher API for this goals.

在JUnit 5中,您可以使用Launcher API实现此目标。

    final LauncherDiscoveryRequest request = LauncherDiscoveryRequestBuilder.request()
            .selectors(
                    selectPackage("path_to_folder_with_tests")
            )
            .build();

    final Launcher launcher = LauncherFactory.create();

    final boolean pathContainsTests = launcher.discover(request).containsTests()
    if (!pathContainsTests) {
        System.out.println("This path is invalid or folder doesn't consist tests");
    }

    final SummaryGeneratingListener listener = new SummaryGeneratingListener();

    launcher.execute(request, listener);

    final TestExecutionSummary summary = listener.getSummary();

    final long containersFoundCount = summary.getContainersFoundCount();
    System.out.println("containers Found Count  " + containersFoundCount);

    final long containersSkippedCount = summary.getContainersSkippedCount();
    System.out.println("containers Skipped Count  " + containersSkippedCount);

    final long testsFoundCount = summary.getTestsFoundCount();
    System.out.println("tests Found Count  " + testsFoundCount);

    final long testsSkippedCount = summary.getTestsSkippedCount();
    System.out.println("tests Skipped Count  " + testsSkippedCount);

#6


1  

Result result = JUnitCore.runClasses(classes);

See http://junit.sourceforge.net/javadoc/org/junit/runner/JUnitCore.html#runClasses(java.lang.Class...)

请参阅http://junit.sourceforge.net/javadoc/org/junit/runner/JUnitCore.html#runClasses(java.lang.Class ...)

#1


78  

Yes, you can. I was doing it couple of times to run diagnostic/smoke tests in production systems. This is a snippet of key part of the code invoking JUnit:

是的你可以。我正在做几次在生产系统中运行诊断/烟雾测试。这是调用JUnit的代码的关键部分的片段:

JUnitCore junit = new JUnitCore();
Result result = junit.run(testClasses);

DON'T use JUnit.main inside your application, it invokes System.exit after tests are finished and thus it may stop JVM process.

不要在应用程序中使用JUnit.main,它会在测试完成后调用System.exit,因此可能会停止JVM进程。

You may want to capture JUnit's "regular" console output (the dots and simple report). This can be easily done by registering TextListener (this class provides this simple report).

您可能想要捕获JUnit的“常规”控制台输出(点和简单报告)。这可以通过注册TextListener轻松完成(此类提供了这个简单的报告)。

Please also be aware of several complications using this kind of method:

请注意使用这种方法的几种并发症:

  1. Testing of any "test framework", including so small one, although is quite simple may be confusing. For example if you want to test if your "test framework" return failure result when one of the tests fails you could (should?) create sample JUnit test that always fails and execute that test with the "test framework". In this case failing test case is actually test data and shouldn't be executed as "normal" JUnit. For an example of such tests you can refer to JUnit's internal test cases.

    测试任何“测试框架”,包括如此小的测试框架,虽然很简单,但可能会令人困惑。例如,如果您想测试当其中一个测试失败时您的“测试框架”是否返回失败结果,您可以(应该?)创建始终失败的示例JUnit测试并使用“测试框架”执行该测试。在这种情况下,失败的测试用例实际上是测试数据,不应该作为“正常”JUnit执行。有关此类测试的示例,您可以参考JUnit的内部测试用例。

  2. If you want to prepare / display your custom report you should rather register your own RunListener, because Result returned by JUnit doesn't contain (directly) information about passed tests and test method (it is only "hardcoded" as a part of test Description).

    如果要准备/显示自定义报告,则应该注册自己的RunListener,因为JUnit返回的结果不包含(直接)有关传递的测试和测试方法的信息(它仅作为测试的一部分“硬编码” )。

#2


11  

As documented in the JUnit FAQ:

如JUnit FAQ中所述:

public static void main(String args[]) {
  org.junit.runner.JUnitCore.main("junitfaq.SimpleTest");
}

#3


10  

The reason why I am asking is my application requires a lot of work to start launch (lots of dependencies and configurations, etc) and using an external testing tool (like JUnit Ant task) would require a lot of work to set up.

我之所以要问的是我的应用程序需要大量的工作来启动启动(许多依赖项和配置等),并且使用外部测试工具(如JUnit Ant任务)需要大量的工作来设置。

You need to remove these dependencies from the code you are testing. The dependencies and configurations are precisely what you are trying to avoid when writing a test framework. For each test, you should be targeting the smallest testable part of an application.

您需要从正在测试的代码中删除这些依赖项。依赖关系和配置正是您在编写测试框架时要避免的。对于每个测试,您应该定位应用程序中最小的可测试部分。

For example, if you require a database connection to execute some process in a class you are trying to test - decouple the database handling object from your class, pass it in via a constructor or setter method, and in your test use a tool like JMock (or write a stub class) to build a fake database handling object. This way you are making sure the tests are not dependent on a particular database configuration, and you are only testing the small portion of code you are interested in, not the entire database handling layer as well.

例如,如果您需要数据库连接来执行您尝试测试的类中的某个进程 - 将数据库处理对象与类分离,通过构造函数或setter方法传递它,并在测试中使用像JMock这样的工具(或编写存根类)来构建虚假的数据库处理对象。这样,您可以确保测试不依赖于特定的数据库配置,并且您只测试您感兴趣的一小部分代码,而不是整个数据库处理层。

It might seem like a lot of work at first, but this kind of refactoring is exactly what your test framework should be fleshing out. You might find it useful to get a book on software testing as a reference for decoupling your dependencies. It will pay off a lot more than trying to bootstrap JUnit from inside your running application.

一开始看起来似乎很多工作,但这种重构正是你的测试框架应该充实的东西。您可能会发现将软件测试的书作为解耦依赖关系的参考是有用的。与尝试从正在运行的应用程序中引导JUnit相比,它将获得更多回报。

#4


2  

According to the JUnit API, JUnitCore has several methods to execute tests inside Java.

根据JUnit API,JUnitCore有几种在Java中执行测试的方法。

Thanks to Tomislav Nakic-Alfirevic for pointing it out.

感谢Tomislav Nakic-Alfirevic指出它。

http://junit.sourceforge.net/javadoc/org/junit/runner/JUnitCore.html

http://junit.sourceforge.net/javadoc/org/junit/runner/JUnitCore.html

#5


2  

In JUnit 5 you can use Launcher API for this goals.

在JUnit 5中,您可以使用Launcher API实现此目标。

    final LauncherDiscoveryRequest request = LauncherDiscoveryRequestBuilder.request()
            .selectors(
                    selectPackage("path_to_folder_with_tests")
            )
            .build();

    final Launcher launcher = LauncherFactory.create();

    final boolean pathContainsTests = launcher.discover(request).containsTests()
    if (!pathContainsTests) {
        System.out.println("This path is invalid or folder doesn't consist tests");
    }

    final SummaryGeneratingListener listener = new SummaryGeneratingListener();

    launcher.execute(request, listener);

    final TestExecutionSummary summary = listener.getSummary();

    final long containersFoundCount = summary.getContainersFoundCount();
    System.out.println("containers Found Count  " + containersFoundCount);

    final long containersSkippedCount = summary.getContainersSkippedCount();
    System.out.println("containers Skipped Count  " + containersSkippedCount);

    final long testsFoundCount = summary.getTestsFoundCount();
    System.out.println("tests Found Count  " + testsFoundCount);

    final long testsSkippedCount = summary.getTestsSkippedCount();
    System.out.println("tests Skipped Count  " + testsSkippedCount);

#6


1  

Result result = JUnitCore.runClasses(classes);

See http://junit.sourceforge.net/javadoc/org/junit/runner/JUnitCore.html#runClasses(java.lang.Class...)

请参阅http://junit.sourceforge.net/javadoc/org/junit/runner/JUnitCore.html#runClasses(java.lang.Class ...)