JUnit5: Surefire插件会对JUnit4测试运行两次。

huangapple go评论75阅读模式
英文:

JUnit5: Surefire plugin runs JUnit4 tests twice

问题

我项目中既有JUnit4测试,也有JUnit5测试。问题在于当我运行 mvn clean install 命令时,JUnit4测试会运行两次(JUnit5测试只运行一次正常)。

我在父项目的pom文件中有以下的surefire-plugin配置(只展示相关依赖部分):

<plugin>
  <groupId>org.apache.maven.plugins</groupId>
  <artifactId>maven-surefire-plugin</artifactId>
  <version>2.22.2</version>
  <configuration>
    <threadCount>1</threadCount>
    <properties>
      <property>
        <name>junit</name>
        <value>false</value>
      </property>
    </properties>
  </configuration>
  <dependencies>
    <dependency>
      <groupId>org.apache.maven.surefire</groupId>
      <artifactId>surefire-testng</artifactId>
      <version>2.22.2</version>
    </dependency>
    <dependency>
      <groupId>org.apache.maven.surefire</groupId>
      <artifactId>surefire-junit-platform</artifactId>
      <version>2.22.2</version>
    </dependency>
  </dependencies>
</plugin>
...
...
<dependency>
  <groupId>org.junit.jupiter</groupId>
  <artifactId>junit-jupiter-engine</artifactId>
  <version>5.6.2</version>
  <scope>test</scope>
</dependency>
<dependency>
  <groupId>org.junit.vintage</groupId>
  <artifactId>junit-vintage-engine</artifactId>
  <version>5.6.2</version>
  <scope>test</scope>
</dependency>
<dependency>
  <!-- needed for https://youtrack.jetbrains.com/issue/IDEA-231927?_ga=2.101965186.223349104.1602977709-1646014256.1600106493 -->
  <groupId>org.junit.platform</groupId>
  <artifactId>junit-platform-launcher</artifactId>
  <version>1.6.2</version>
  <scope>test</scope>
</dependency>

我还在子项目中复制了以上的surefire-plugin配置,以确保它不会被其他内容覆盖。但是仍然会导致JUnit4测试运行两次。

以下是生效的pom文件中的surefire-plugin部分:

<plugin>
  <artifactId>maven-surefire-plugin</artifactId>
  <version>2.22.2</version>
  <configuration>
    <threadCount>1</threadCount>
    <properties>
      <property>
        <name>junit</name>
        <value>false</value>
      </property>
    </properties>
  </configuration>
  <dependencies>
    <dependency>
      <groupId>org.apache.maven.surefire</groupId>
      <artifactId>surefire-testng</artifactId>
      <version>2.22.2</version>
    </dependency>
    <dependency>
      <groupId>org.apache.maven.surefire</groupId>
      <artifactId>surefire-junit-platform</artifactId>
      <version>2.22.2</version>
    </dependency>
    <dependency>
      <groupId>org.apache.maven.surefire</groupId>
      <artifactId>surefire-junit47</artifactId>
      <version>2.19.1</version>
      <scope>compile</scope>
    </dependency>
  </dependencies>
</plugin>

通过使用 -X 选项进行调试,我认为问题是因为 surefire-junit47 也被添加到了surefire-plugin的提供者中,surefire-junit-platform 运行了一次JUnit4测试,然后由 surefire-junit47 提供者再次运行了一次。如果这是可能的原因,那么如何防止将其添加到surefire-plugin的依赖项中呢?我尝试使用 &lt;classpathDependencyExcludes&gt;,但没有帮助,有效的pom文件仍然包含 surefire-junit47

此外,是否有方法可以在同时拥有 surefire-junit47surefire-junit-platform 提供者的情况下避免JUnit4运行两次呢?

---------- 更新 ------------

实际问题是,我的项目继承了一个父pom,该pom在surefire-plugin中声明了 surefire-junit47 依赖。因此,实际上我的项目同时拥有 surefire-junit-platformsurefire-junit47,这导致了JUnit4测试运行两次。

英文:

I have both JUnit4 and JUnit5 tests in my project. The problem is that when I run mvn clean install the JUnit4 tests are run twice (JUnit5 tests run fine and once only).

I have the following surefire-plugin configuration (showing only relevant dependencies) in my parent project pom

&lt;plugin&gt;
  &lt;groupId&gt;org.apache.maven.plugins&lt;/groupId&gt;
  &lt;artifactId&gt;maven-surefire-plugin&lt;/artifactId&gt;
  &lt;version&gt;2.22.2&lt;/version&gt;
  &lt;configuration&gt;
    &lt;threadCount&gt;1&lt;/threadCount&gt;
    &lt;properties&gt;
      &lt;property&gt;
        &lt;name&gt;junit&lt;/name&gt;
        &lt;value&gt;false&lt;/value&gt;
      &lt;/property&gt;
    &lt;/properties&gt;
  &lt;/configuration&gt;
  &lt;dependencies&gt;
    &lt;dependency&gt;
      &lt;groupId&gt;org.apache.maven.surefire&lt;/groupId&gt;
      &lt;artifactId&gt;surefire-testng&lt;/artifactId&gt;
      &lt;version&gt;2.22.2&lt;/version&gt;
    &lt;/dependency&gt;
    &lt;dependency&gt;
      &lt;groupId&gt;org.apache.maven.surefire&lt;/groupId&gt;
      &lt;artifactId&gt;surefire-junit-platform&lt;/artifactId&gt;
      &lt;version&gt;2.22.2&lt;/version&gt;
    &lt;/dependency&gt;
  &lt;/dependencies&gt;
&lt;/plugin&gt;
...
...
&lt;dependency&gt;
  &lt;groupId&gt;org.junit.jupiter&lt;/groupId&gt;
  &lt;artifactId&gt;junit-jupiter-engine&lt;/artifactId&gt;
  &lt;version&gt;5.6.2&lt;/version&gt;
  &lt;scope&gt;test&lt;/scope&gt;
&lt;/dependency&gt;
&lt;dependency&gt;
  &lt;groupId&gt;org.junit.vintage&lt;/groupId&gt;
  &lt;artifactId&gt;junit-vintage-engine&lt;/artifactId&gt;
  &lt;version&gt;5.6.2&lt;/version&gt;
  &lt;scope&gt;test&lt;/scope&gt;
&lt;/dependency&gt;
&lt;dependency&gt;
  &lt;!-- needed for https://youtrack.jetbrains.com/issue/IDEA-231927?_ga=2.101965186.223349104.1602977709-1646014256.1600106493 --&gt;
  &lt;groupId&gt;org.junit.platform&lt;/groupId&gt;
  &lt;artifactId&gt;junit-platform-launcher&lt;/artifactId&gt;
  &lt;version&gt;1.6.2&lt;/version&gt;
  &lt;scope&gt;test&lt;/scope&gt;
&lt;/dependency&gt;

I replicated the above surefire-plugin in the child project as well to make sure it does not get overridden by anything. But still, the JUnit4 tests are run twice.

Following is the surefire-plugin portion in the effective pom -

&lt;plugin&gt;
  &lt;artifactId&gt;maven-surefire-plugin&lt;/artifactId&gt;
  &lt;version&gt;2.22.2&lt;/version&gt;
  &lt;configuration&gt;
    &lt;threadCount&gt;1&lt;/threadCount&gt;
    &lt;properties&gt;
      &lt;property&gt;
        &lt;name&gt;junit&lt;/name&gt;
        &lt;value&gt;false&lt;/value&gt;
      &lt;/property&gt;
    &lt;/properties&gt;
  &lt;/configuration&gt;
  &lt;dependencies&gt;
    &lt;dependency&gt;
      &lt;groupId&gt;org.apache.maven.surefire&lt;/groupId&gt;
      &lt;artifactId&gt;surefire-testng&lt;/artifactId&gt;
      &lt;version&gt;2.22.2&lt;/version&gt;
    &lt;/dependency&gt;
    &lt;dependency&gt;
      &lt;groupId&gt;org.apache.maven.surefire&lt;/groupId&gt;
      &lt;artifactId&gt;surefire-junit-platform&lt;/artifactId&gt;
      &lt;version&gt;2.22.2&lt;/version&gt;
    &lt;/dependency&gt;
    &lt;dependency&gt;
      &lt;groupId&gt;org.apache.maven.surefire&lt;/groupId&gt;
      &lt;artifactId&gt;surefire-junit47&lt;/artifactId&gt;
      &lt;version&gt;2.19.1&lt;/version&gt;
      &lt;scope&gt;compile&lt;/scope&gt;
    &lt;/dependency&gt;
  &lt;/dependencies&gt;
&lt;/plugin

On doing some debugging with -X option I think the reason is because surefire-junit47 also gets added in the providers for surefire-plugin, surefire-junit-platform runs the junit4 tests once and they are run again by surefire-junit47 provider. If that is a probable reason then how can I prevent this from getting added to surefire-plugin dependencies? I tried &lt;classpathDependencyExcludes&gt; but that didn't help and the effective pom still contained surefire-junit47.

Also is there any way to avoid JUnit4 running twice even with having both providers (surefire-junit47 and surefire-junit-platform)?

---------- Update ------------

I also have set the junit property to false in the configuration for surefire to prevent testng provider running the junit tests (as suggested here). But still, I am getting two runs of JUnit4 tests. My guess is that somehow surefire-junit47(which is getting added mysteriously) and surefire-junit-platform are acting weird together to cause duplicated runs.

---------- Update ------------

The actual problem turns out that my project is inheriting a parent pom which has declared a dependency surefire-junit47 in surefire-plugin. So effectively my project has both surefire-junit-platform and surefire-junit47 which results in dual runs of JUnit4 tests.

答案1

得分: 2

我已经能够复现你的问题。你遇到了一个在这里描述的情况:

> TestNG 6.5.1 及更高版本支持在当前 Maven 项目中运行 TestNG 和 JUnit 4.x。(...)
>
> 你可能想要运行两个提供者,例如 surefire-junit47surefire-testng,并通过设置属性 junit=false 来避免在 surefire-testng 提供者中运行 JUnit 测试。

因此,请将你的 Surefire 插件配置更改为:

&lt;configuration&gt;
  &lt;threadCount&gt;1&lt;/threadCount&gt;
  &lt;properties&gt;
    &lt;!-- 避免在 TestNG 引擎中运行 JUnit 4 测试 --&gt;
    &lt;property&gt;
      &lt;name&gt;junit&lt;/name&gt;
      &lt;value&gt;false&lt;/value&gt;
    &lt;/property&gt;
  &lt;/properties&gt;
&lt;/configuration&gt;

更新:如何(伪)排除直接的 Maven 插件依赖:

好的,供参考,我想出了一种通过使用虚拟替代来“排除”依赖的方法。

首先,在项目的根 POM 中添加一个模块,但不要将根 POM 指定为其父级。只需确保该模块在同一 Reactor 中构建。或者,你还可以为其创建一个单独的项目,并确保其生成的构件位于公司的存储库中。

该模块的 POM 如下所示:

&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;
&lt;project xmlns=&quot;http://maven.apache.org/POM/4.0.0&quot; xmlns:xsi=&quot;http://www.w3.org/2001/XMLSchema-instance&quot;
  xsi:schemaLocation=&quot;http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd&quot;&gt;
  &lt;modelVersion&gt;4.0.0&lt;/modelVersion&gt;

  &lt;groupId&gt;org.apache.maven.surefire&lt;/groupId&gt;
  &lt;artifactId&gt;surefire-junit47&lt;/artifactId&gt;
  &lt;version&gt;dummy&lt;/version&gt;
&lt;/project&gt;

在你希望在其中停用 JUnit 4.7 引擎,以便在 JUnit 5 平台上运行你的 JUnit 4 测试的子 POM 中,你可以像这样操作:

&lt;plugin&gt;
  &lt;groupId&gt;org.apache.maven.plugins&lt;/groupId&gt;
  &lt;artifactId&gt;maven-surefire-plugin&lt;/artifactId&gt;
  &lt;version&gt;${maven-surefire.version}&lt;/version&gt;
  &lt;configuration&gt;
    &lt;threadCount&gt;1&lt;/threadCount&gt;
    &lt;properties&gt;
      &lt;!-- 避免在 TestNG 引擎中运行 JUnit 4 测试 --&gt;
      &lt;property&gt;
        &lt;name&gt;junit&lt;/name&gt;
        &lt;value&gt;false&lt;/value&gt;
      &lt;/property&gt;
    &lt;/properties&gt;
  &lt;/configuration&gt;
  &lt;dependencies&gt;
    &lt;dependency&gt;
      &lt;!-- 使用一个空的虚拟替代来停用 JUnit 4.7 引擎 --&gt;
      &lt;groupId&gt;org.apache.maven.surefire&lt;/groupId&gt;
      &lt;artifactId&gt;surefire-junit47&lt;/artifactId&gt;
      &lt;version&gt;dummy&lt;/version&gt;
    &lt;/dependency&gt;
  &lt;/dependencies&gt;
&lt;/plugin&gt;

&lt;!-- (...) --&gt;

&lt;dependencies&gt;
  &lt;dependency&gt;
    &lt;groupId&gt;org.apache.maven.surefire&lt;/groupId&gt;
    &lt;artifactId&gt;surefire-junit47&lt;/artifactId&gt;
    &lt;version&gt;dummy&lt;/version&gt;
  &lt;/dependency&gt;
&lt;/dependencies&gt;

这个方法非常丑陋,如果可能的话,我仍然建议重构父 POM。无论如何,它有效。现在,你的 JUnit 4 测试只会运行一次,即在 JUnit 5 平台上与 JUnit 5 测试、Spock 2.0 测试或其他测试一起运行。


更新 2: 在你提供了一个在 GitHub 上的 MCVE(最小可复现示例) 之后,我给你发送了一个 pull 请求,实现了我在上一个更新中提到的解决方法。重要的提交是 这个

英文:

I was able to reproduce your problem. You are running into a situation described here:

> TestNG 6.5.1 and higher provides support to run TestNG and JUnit 4.x in current Maven project. (...)
>
> You may want to run two providers, e.g. surefire-junit47 and surefire-testng, and avoid running JUnit tests within surefire-testng provider by setting property junit=false.

So please change your Surefire plugin configuration to:

&lt;configuration&gt;
  &lt;threadCount&gt;1&lt;/threadCount&gt;
  &lt;properties&gt;
    &lt;!-- Avoid running JUnit 4 tests in TestNG engine --&gt;
    &lt;property&gt;
      &lt;name&gt;junit&lt;/name&gt;
      &lt;value&gt;false&lt;/value&gt;
    &lt;/property&gt;
  &lt;/properties&gt;
&lt;/configuration&gt;

Update: How to (pseudo) exclude a direct Maven plugin dependency:

Okay, FWIW I came up with a hacky way to "exclude" a dependency by overriding it with a dummy.

First you add a module to your project's root POM, but without specifying the root POM as its parent. Just make sure the module is built in the same reactor. Alternatively, you can also create a separate project for it and make sure its resulting artifact is in your company's repository.

The module POM looks like this:

&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;
&lt;project xmlns=&quot;http://maven.apache.org/POM/4.0.0&quot; xmlns:xsi=&quot;http://www.w3.org/2001/XMLSchema-instance&quot;
  xsi:schemaLocation=&quot;http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd&quot;&gt;
  &lt;modelVersion&gt;4.0.0&lt;/modelVersion&gt;

  &lt;groupId&gt;org.apache.maven.surefire&lt;/groupId&gt;
  &lt;artifactId&gt;surefire-junit47&lt;/artifactId&gt;
  &lt;version&gt;dummy&lt;/version&gt;
&lt;/project&gt;

In your child POM where you wish to deactivate the JUnit 4.7 engine in favour of running your JUnit 4 tests on the JUnit 5 platform, you can do something like this:

&lt;plugin&gt;
  &lt;groupId&gt;org.apache.maven.plugins&lt;/groupId&gt;
  &lt;artifactId&gt;maven-surefire-plugin&lt;/artifactId&gt;
  &lt;version&gt;${maven-surefire.version}&lt;/version&gt;
  &lt;configuration&gt;
    &lt;threadCount&gt;1&lt;/threadCount&gt;
    &lt;properties&gt;
      &lt;!-- Avoid running JUnit 4 tests in TestNG engine --&gt;
      &lt;property&gt;
        &lt;name&gt;junit&lt;/name&gt;
        &lt;value&gt;false&lt;/value&gt;
      &lt;/property&gt;
    &lt;/properties&gt;
  &lt;/configuration&gt;
  &lt;dependencies&gt;
    &lt;dependency&gt;
      &lt;!-- Deactivate JUnit 4.7 engine by overriding it with an empty dummy --&gt;
      &lt;groupId&gt;org.apache.maven.surefire&lt;/groupId&gt;
      &lt;artifactId&gt;surefire-junit47&lt;/artifactId&gt;
      &lt;version&gt;dummy&lt;/version&gt;
    &lt;/dependency&gt;
  &lt;/dependencies&gt;
&lt;/plugin&gt;

&lt;!-- (...) --&gt;

&lt;dependencies&gt;
  &lt;dependency&gt;
    &lt;groupId&gt;org.apache.maven.surefire&lt;/groupId&gt;
    &lt;artifactId&gt;surefire-junit47&lt;/artifactId&gt;
    &lt;version&gt;dummy&lt;/version&gt;
  &lt;/dependency&gt;
&lt;/dependencies&gt;

This is super ugly and I would still recommend refactoring the parent POM, if possible. Anyway, it works. Now your JUnit 4 tests only run once, i.e. inside the JUnit 5 platform alongside JUnit 5 tests, Spock 2.0 tests or what have you.


Update 2: After you provided an MCVE on GitHub, I sent you a pull request implementing exactly the workaround I mentioned in the previous update. The important commit is this one.

huangapple
  • 本文由 发表于 2020年10月18日 07:50:10
  • 转载请务必保留本文链接:https://go.coder-hub.com/64408418.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定