【问题标题】:How to avoid surefire test to be run in parallel如何避免万无一失的测试并行运行
【发布时间】:2018-07-03 07:39:36
【问题描述】:

我在这里有一个应用程序,其中单元测试的编写方式不能并行运行。

当使用 maven 运行测试时,其中一些会因为这个原因而失败。 我可以通过执行

来验证它们是否并行运行
System.out.println(System.currentTimeMillis() +">>> executing testXXX");
System.out.println(System.currentTimeMillis() +">>> finished  testXXX");

在每个方法的开始和结束。 输出是:

1530602546964>>> executing testInstantiation                                                                                                                         
1530602547036<<< finished  testInstantiation                                                                                                                         
1530602547042>>> executing testSimilarNamedResources                                                                                                                 
1530602547050>>> executing testTranslateWithMissingKey                                                                                                               
1530602547051>>> executing testTryTranslateWithMissingKey                                                                                                            
1530602547051<<< finished  testTryTranslateWithMissingKey                                                                                                            
1530602547051>>> executing testTranslationMapWithMissingKey                                                                                                          
1530602547055>>> executing testSilentlyIgnoringExceptionTranslationMapWithMissingKey                                                                                 
1530602547055<<< finished  testSilentlyIgnoringExceptionTranslationMapWithMissingKey   

正如我们所见,在 testSimilarNamedResources 启动后,其他一些测试也启动了。

我尝试将surefire插件配置为不并行运行:

<build>                                                                                                                                                           
   <plugins>
     <plugin>
       <groupId>org.apache.maven.plugins</groupId>
       <artifactId>maven-surefire-plugin</artifactId>
       <version>2.22.0</version>
       <configuration>
         <!--parallel>false</parallel-->
         <threadCount>1</threadCount>
         <perCoreThreadCount>false</perCoreThreadCount>
       </configuration>
     </plugin>
   </plugins>
</build>

但它仍然并行执行这些测试。 我使用 -X 选项运行 mvn 以查看我的配置是否已应用并得到以下输出:

$ mvn -X test | grep -iE "(parallel|threadcount)"                                                                                                                
  <parallel>${parallel}</parallel>                                                                                                                               
  <parallelMavenExecution default-value="${session.parallel}"/>                                                                                                  
  <parallelOptimized default-value="true">${parallelOptimized}</parallelOptimized>                                                                               
  <parallelTestsTimeoutForcedInSeconds>${surefire.parallel.forcedTimeout}<parallelTestsTimeoutForcedInSeconds>                                                   
  <parallelTestsTimeoutInSeconds>${surefire.parallel.timeout}<parallelTestsTimeoutInSeconds>                                                                     
  <perCoreThreadCount default-value="true">false</perCoreThreadCount>                                                                                            
  <threadCount>0</threadCount>                                                                                                                                   
  <threadCountClasses default-value="0">${threadCountClasses}</threadCountClasses>                                                                               
  <threadCountMethods default-value="0">${threadCountMethods}</threadCountMethods>                                                                               
  <threadCountSuites default-value="0">${threadCountSuites}</threadCountSuites>                                                                                  
[DEBUG]   (f) parallelMavenExecution = false                                                                                                                     
[DEBUG]   (s) parallelOptimized = true                                                                                                                           
[DEBUG]   (s) perCoreThreadCount = false                                                                                                                         
[DEBUG]   (s) threadCount = 0                                                                                                                                    
[DEBUG]   (s) threadCountClasses = 0                                                                                                                             
[DEBUG]   (s) threadCountMethods = 0                                                                                                                             
[DEBUG]   (s) threadCountSuites = 0                    

我是否遗漏了插件配置中的某些内容?

更新:

我已经放弃了。行为太奇怪了。试图创建简单的样本没有用。这些测试不是并行运行的。我不知道为什么会出现这种情况。 我们将修改整个代码,因此也会修改单元测试。不再需要寻找解决方案,但它仍然让我感到困惑,为什么它会表现出这种奇怪的行为......

【问题讨论】:

  • 我在这里有一个应用程序,其中单元测试的编写方式无法并行运行 - 它们的编写方式错误。测试必须能够独立于其他测试运行。如果您的测试依赖于其他测试的结果,则它不是一个好的测试,您应该重新设计它以使其独立。
  • @BackSlash 我知道。这不是我的代码。但它就是这样。在测试(可能还有代码)被重新设计以支持并行运行之前,我想让它正确地执行测试。
  • 我不确定,但我希望它是不可能的,因为测试是并行运行的,而不依赖于其他测试。所以它可能是图书馆不允许你这样做。不过我可能是错的。
  • 顺便说一句:测试不依赖彼此。它们在并行运行时相互干扰。这似乎是由于使用了一些静态可变数据造成的。
  • 不能。默认情况下:surefire(此处为 JUnit runner)不会并行执行测试。顺序测试执行确实是默认行为。所以你不需要设置任何东西来获得它。此外,调试输出确认没有启用并行执行:&gt; [DEBUG] (f) parallelMavenExecution = false。请提供一个最小、完整且可验证的示例。

标签: java maven junit maven-surefire-plugin


【解决方案1】:

我建议您遵循以下指南:

从 maven-surefire-plugin:2.18 开始,您可以在 JUnit 测试的 Java 类(纯测试类、Suite、Parameterized 等)上应用 JCIP 注解 @net.jcip.annotations.NotThreadSafe 以便执行它在单个线程实例中。线程的名称为 maven-surefire-plugin@NotThreadSafe 并在测试运行结束时执行。 https://maven.apache.org/surefire/maven-surefire-plugin/examples/fork-options-and-parallel-execution.html#Parallel_Test_Execution_and_Single_Thread_Execution

就像其他人所说的那样,它们确实应该被重写,并且在例外情况下,绝对不能并行运行的测试应该被注释。

对于您的插件定义,我建议您让它并行运行,因为它在现代机器上会更快。

我的定义为:

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-surefire-plugin</artifactId>
    <version>${maven-surefire-plugin.version}</version>
    <configuration>
        <useUnlimitedThreads>true</useUnlimitedThreads>
        <runOrder>random</runOrder>
        <redirectTestOutputToFile>true</redirectTestOutputToFile>
        <rerunFailingTestsCount>1</rerunFailingTestsCount>
        <parallel>methods</parallel>
        <forkedProcessExitTimeoutInSeconds>2</forkedProcessExitTimeoutInSeconds>
    </configuration>
</plugin>

【讨论】:

  • “真的应该重写”——你可能不希望并行运行测试的原因有很多。就我而言,如果测试并行运行,我将无法读取日志文件。我会对临时解决方案感到满意。不要这么快就放弃对某个功能的需求。
【解决方案2】:

我只花了几个小时来处理这个问题,最后通过将 forkCount 显式设置为 1 来解决它。默认值应该是 1,但它确实不像它。

我通过在几个测试用例中打印正在运行的 JVM 的唯一名称(使用 ManagementFactory.getRuntimeMXBean().getName())确认了这一点,每个测试用例都在自己的类中,以及 30 秒的 Thread.sleep() 调用。在没有明确设置 forkCount 的情况下,sleep() 不会阻止其他测试用例的执行 - 教学测试显然同时运行,而 getName() 返回明显不同的值。当我将 forkCount 显式设置为 1 时,sleep() 会按预期调用阻塞执行,并且 getName() 每次都返回相同的值。

另外,只是想添加@NotThreadSafe 显然是not working as intended。我先试了一下,没有运气。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-02-26
    • 1970-01-01
    • 2018-04-01
    • 2010-10-14
    • 2020-06-01
    相关资源
    最近更新 更多