surefire如何决定测试框架?

How Does surefire decide on the Test framework?

我一直在尝试了解 Surefire 插件如何在内部决定使用哪个测试框架(TestNG、Jupiter、Junit4 等)

它是否使用反射并尝试在类路径中查找每个框架的存在?
(查看依赖项,Surefire 似乎在其传递依赖项中附带了 junit4 - junit:JUnit:jar:4.12)

可以显式传递提供程序(test-framework 类型),设置额外的插件依赖项,例如对于 TestNG:

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-surefire-plugin</artifactId>
    <version>3.0.0-M5</version>
    <dependencies>
      <dependency>
        <groupId>org.apache.maven.surefire</groupId>
        <artifactId>surefire-testng</artifactId>
        <version>3.0.0-M5</version>
      </dependency>
    </dependencies>
  </plugin>

如果没有指定

Surefire normally automatically selects which test-framework provider to use based on the version of TestNG/JUnit present in your project's classpath.

来自此文档:

https://maven.apache.org/surefire/maven-surefire-plugin/examples/providers.html

Surefire 插件如何在内部决定使用哪个测试框架

让我们看看它是如何实现的。

ProviderInfo 方法接口 boolean isApplicable();

ProviderInfo.java

我在 class AbstractSurefireMojo.java

中找到了多个实现

AbstractSurefireMojo.java

用于:

  • TestNgProviderInfo
  • JUnit3ProviderInfo
  • JUnit4ProviderInfo
  • JUnitPlatformProviderInfo
  • JUnitCoreProviderInfo
  • DynamicProviderInfo

还有一个受保护的方法 protected List<ProviderInfo> createProviders( TestClassPath testClasspath ) 引用了所有这些实现。

protected List<ProviderInfo> createProviders( TestClassPath testClasspath )
        throws MojoExecutionException
    {
        Artifact junitDepArtifact = getJunitDepArtifact();
        return providerDetector.resolve( new DynamicProviderInfo( null ),
            new JUnitPlatformProviderInfo( getJUnit5Artifact(), testClasspath ),
            new TestNgProviderInfo( getTestNgArtifact() ),
            new JUnitCoreProviderInfo( getJunitArtifact(), junitDepArtifact ),
            new JUnit4ProviderInfo( getJunitArtifact(), junitDepArtifact ),
            new JUnit3ProviderInfo() );
    }

ProviderDetector class 在 resolve 方法中为每个 providerInfo 调用 isApplicable()

ProviderDetector.java

看起来第一个适用的已被选中:

private Optional<ProviderInfo> autoDetectOneWellKnownProvider( ProviderInfo... wellKnownProviders )
    {
        Optional<ProviderInfo> providerInfo = stream( wellKnownProviders )
            .filter( ProviderInfo::isApplicable )
            .findFirst();

        providerInfo.ifPresent( p -> logger.info( "Using auto detected provider " + p.getProviderName() ) );

        return providerInfo;
    }