"Unit testing" Maven 构建

"Unit testing" a Maven build

我有一个复杂的 Maven 构建,我想要一些自动检查构建生成的 JAR 文件和 POM 文件是否确实包含我期望它们包含的内容。

例如,我想检查清单文件中是否存在 Automatic-Module-Name 条目。这是一个多版本 JAR,因此我想检查 META-INF/versions 中是否存在正确的 class 文件。我要发布到 Maven Central,所以我还想检查生成的 pom 文件是否包含项目需要的依赖项,但是为我也发布的 fat jar 生成的 pom 文件, 不包含这些依赖项。

基本上,我想对我的构建进行单元测试:)。

不幸的是,对此很难 google,因为我用来描述它的词(“测试”、“验证”)在 Maven 中已经具有非常具体的不同含义。

有什么好的方法吗?我更喜欢 Maven 插件,因为我显然已经在使用它,但我也对其他东西持开放态度。

正如@khmarbaise 在评论中建议的那样,我最终创建了一个新的 Maven 子模块。在它的 pom 中,我使用 copy-rename-maven-plugin 复制了我实际想要检查的文件,如下所示:

<plugin>
    <groupId>com.coderplus.maven.plugins</groupId>
    <artifactId>copy-rename-maven-plugin</artifactId>
    <version>${version.copy-rename-maven-plugin}</version>
    <executions>
        <execution>
            <id>copy-artifacts</id>
            <phase>compile</phase>
            <goals>
                <goal>copy</goal>
            </goals>
            <configuration>
                <fileSets>
                    <fileSet>
                        <sourceFile>${project.basedir}../core/target/.flattened-pom.xml</sourceFile>
                        <destinationFile>${project.basedir}/src/test/resources/flattened.pom</destinationFile>
                    </fileSet>
                    <fileSet>
                        <sourceFile>${project.basedir}../core/target/myArtifactId-${project.version}.jar</sourceFile>
                        <destinationFile>${project.basedir}/src/test/resources/myArtifactId.jar</destinationFile>
                    </fileSet>
                    <!-- more fileSets here -->
                </fileSets>
            </configuration>
        </execution>
    </executions>
</plugin>

然后我能够读取 pom 文件并对其进行断言。我最终使用了 Java 的 built-in XPath API,但你可以使用任何东西。

我还可以通过将 JAR 文件转换为 NIO 文件系统来读取它:

var filename = "myArtifactId.jar"; // or "flattened.pom"
var file = getClass().getClassLoader().getResource(filename);
var uri = URI.create("jar:" + file.toURI().toString());
FileSystem fs = FileSystems.newFileSystem(uri, Map.of());

您可以获得文件列表:

var path = fs.getPath("/");
Set<String> filenames = StreamSupport
    .stream(walk.spliterator(), false)
    .map(Path::toString)
    .collect(Collectors.toSet());

或者读取一个文件的内容:

var path = fs.getPath("/META-INF/MANIFEST.MF");
var out = new ByteArrayOutputStream();
Files.copy(path, out);
String content = out.toString();
assertTrue(content.contains("Multi-Release: true"));
var path = fs.getPath("/com/example/MyClass.class");
var out = new ByteArrayOutputStream();
Files.copy(path, out);
byte[] content = out.toByteArray();
var actualVersion = content[7]; // the major version of the class file is at this location
assertEquals(52, actualVersion); // 52 = Java 8

(请注意,对于这个答案,我没有费心去处理异常或关闭资源;你必须自己做。)