簡體   English   中英

設置多版本 JAR 單元測試

[英]Setting up multi-release JAR unit tests

我有一個使用大量反射的項目,也在“新”Java 功能(例如記錄和密封類)上。 我正在寫這樣的 class :

public class RecordHelper {
    public static boolean isRecord(Class<?> type) {
        return type.isRecord();
    }
}

當然,這只適用於 Java 16 及更高版本,所以我嘗試設置一個多版本 JAR 文件,默認實現如下:

public class RecordHelper {
    public static boolean isRecord(Class<?> type) {
        return false;
    }
}

我已經能夠使用 Baeldung 上的這篇文章使用 Maven 進行設置,並且效果很好。 這很好,因為它不依賴於不同版本的單獨配置文件,這使我的 pom 文件保持干凈。

但現在我需要編寫測試。

我希望能夠在我想要支持的所有平台上運行測試套件,這意味着從 JDK 8 及更高版本的所有平台。 (我不介意在運行測試之前在不同的 JDK 上編譯。)當然,在 JDK 16 及更高版本上,我還想測試與記錄相關的東西(在 17 及更高版本上,密封類),這意味着我必須編譯一些記錄,這意味着我將不可避免地有一些 class 文件不適用於舊 JDK。

在我看來,使用多版本 JAR 文件進行測試也是有意義的,其中記錄測試放在META-INF/versions中的適當位置,但當然測試通常不打包在JAR,所以這不起作用。

有沒有辦法讓這個在單模塊 Maven 項目中工作而沒有太多重復?

當然,隨着 JDK 版本的上升,它必須“累積”測試類,例如在 JDK 8 上我只有“常規”測試類,在 JDK 16 上我有常規和java16測試類,在 JDK 17 上我有普通的、 java16的和java17的。 在Maven中我還沒有找到一種簡潔的表達方式,但我不是Maven專家。

還是我看錯了方向,是否最好制作一個多模塊 Maven 項目,主代碼在一個模塊中,測試在另一個模塊中,然后生成一個多模塊 jar 進行測試? 如果是這樣,我將如何在不同的 JDK 上運行這個 jar 文件?

正如@khmarbaise 在問題下方的評論之一中所建議的那樣,我最終創建了一個多模塊構建。 他還舉了一個例子

使用名為corem16m17等的模塊。我可以將大部分測試放在core模塊中,並將 JDK 特定的測試放在相應的模塊中。 I can even test the integration of the JDK-specific code with the rest of the core module, because apparently in this setup, Maven picks the implementation of a class in m17 over the implementation of the same class in core , thereby simulating what happens in一個真正的多版本 jar 文件。 我不能 100% 確定這是否是巧合編程,但它確實有效

多模塊方法的另一個優點是,如果我在特定於 JDK 的子模塊中使用新的語言功能,我的 IDE 就會理解它。 使用我在問題中引用的 Baeldung 文章中的方法,這是行不通的,我看到到處都是曲線。

為了測試不同 JDK 上的構建,我使用在 JDK 版本上激活的配置文件,以及 select 適當的子模塊,如下所示:

        <profile>
            <id>modules-jdk8</id>
            <activation>
                <jdk>[1.8,11)</jdk>
            </activation>
            <modules>
                <module>core</module>
            </modules>
        </profile>

        <profile>
            <id>modules-jdk16</id>
            <activation>
                <jdk>[16,17)</jdk>
            </activation>
            <modules>
                <module>core</module>
                <module>m16</module>
            </modules>
        </profile>

        <profile>
            <id>modules-jdk17</id>
            <activation>
                <jdk>[17,)</jdk>
            </activation>
            <modules>
                <module>core</module>
                <module>m16</module>
                <module>m17</module>
                <module>release</module>
            </modules>
        </profile>

(也許使用工具鏈的方法會更好。)

請注意,還必須有一個release模塊,它依賴於所有其他模塊,並使用 Maven 程序集插件來實際創建 jar 文件,並將特定於 JDK 的類放置在 Z68995FC432492D404 中的適當目錄中

我已經為除release模塊之外的所有模塊添加了<maven.install>true</maven.install>屬性,因此只有實際的多版本 jar 文件將安裝到我的本地存儲庫中。 這很重要,因為我也想發布到 Maven 中央,我不想亂扔各種半成品 jar 文件。

要測試 MRJAR,必須將類打包為 jar,因此不要對target/classes使用surefire,而是在verify階段使用故障安全。 而且您必須至少運行兩次,每個目標 Java 版本一次。 我會編寫一個單元測試,它適用於所有 Java 版本,但可能會跳過某些測試。

import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.junit.jupiter.api.Assumptions.assumeTrue;

import org.junit.jupiter.api.Test;

class RecordHelperTest
{

    @Test
    void isNotARecord()
    {
        assertFalse( RecordHelper.isRecord(Object.class));
    }

    @Test
    void isARecord() throws Exception
    {
        assumeTrue( Integer.parseInt( System.getProperty( "java.specification.version" ) ) >= 16 );
        
        Class c = Class.forName( "jdk.net.UnixDomainPrincipal" );
        assertTrue( RecordHelper.isRecord(c));
    }

}

如何運行它兩次,這取決於您,例如使用不同的工具鏈配置故障安全插件兩次,或者依賴一個 CI 服務器,它使用兩個 JDK 構建項目。

https://maven.apache.org/plugins/maven-compiler-plugin/multirelease.html描述了幾個選項及其優缺點。

Maven Invoker Plugin可用於此目的。

遵循插件建議的標准目錄布局並假設版本 8、11 和 16 作為 JDK 目標,JDK 特定測試應在單獨的目錄中構建:

  • src/it/jdk-8用於針對 JDK 8 的測試。
  • src/it/jdk-11用於針對 JDK 11 的測試。
  • src/it/jdk-16用於針對 JDK 16 的測試。

每個組都應該有自己的 POM,其中 Java 版本在maven-compiler-plugin配置中指定,例如使用maven.compiler.release屬性。

每個測試組可以在多個 Java 版本上運行,而無需復制測試類。 例如,要在 Java 11 和 16 執行上運行 JDK 11 測試:

  • 應使用maven-jar-plugin在 JDK 11 相關 POM 中創建測試 JAR
  • 測試 JAR 應該安裝在調用者使用的本地 Maven 存儲庫中(可以為測試特定組設置invoker.goals = install
  • 測試 JAR 應聲明為依賴項,並使用dependenciesToScan參數添加到 JDK 16 相關 POM 的 Maven Surefire 插件配置中。

優點

  • 單模塊項目不需要切換到僅用於測試執行的多模塊設置。
  • 所有的復雜性都被鎖定在src/it中。

缺點

  • Files under src/it are not IDE friendly, eg, the src/it/jdk-*/pom.xml files are not detected as Maven projects and the src/it/jdk-*/src/test subdirectories are not detected as test來源根。

完整示例可在https://github.com/scordio/invoker-plugin-example獲得。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM