"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
(请注意,对于这个答案,我没有费心去处理异常或关闭资源;你必须自己做。)
我有一个复杂的 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
(请注意,对于这个答案,我没有费心去处理异常或关闭资源;你必须自己做。)