使用Maven构建单独的JAR文件,以便对自定义类加载器进行unit testing

作为我当前项目的一部分,我创建了一个自定义类加载器。 自定义加载器的部分unit testing涉及使用一些JAR文件来演示加载器的正确行为。

我想在运行实际的unit testing之前从Java源构建测试JAR文件。 此外,测试JAR文件在运行unit testing时不能在类路径上,因为我想在测试执行期间动态加载它们。

是否有一种标准模式可以实现这种“在测试阶段之前在一侧构建一些JAR但是将它们排除在类路径之外”的要求? 我不敢相信我是第一个尝试使用Maven 2的人,但我似乎无法找到合适的POM结构和依赖关系。 通常我最终会在测试阶段之前没有构建一些测试jar,但是我也遇到了不一致的构建顺序的问题,导致构建在一台机器上正常工作,但是无法构建一些测试另一个jar子。

最简单的方法是设置另一个项目来打包测试jar的类,然后将其设置为正常的测试范围依赖项。

如果您不希望/不能这样做,您可以使用程序集插件在process-test-classes阶段创建一个jar(即在编译测试之后但在执行测试之前)。 下面的配置将调用程序集插件,在目标目录的该阶段创建一个名为classloader-test-deps的jar。 然后,您的测试可以根据需要使用该jar。

程序集插件使用程序集描述符(在src / main / assembly中,称为test-assembly.xml)来打包target / test-classes的内容。 我已经设置了一个filter来包含com.test包及其子项的内容。 这假设您有一些包名称约定,您可以应用jar的内容。

默认情况下,程序集插件会将jar作为附加工件附加,通过将attach指定为false,它将不会被安装/部署。

  maven-assembly-plugin 2.2-beta-2   create-test-dependency process-test-classes  single   classloader-test-deps false  src/main/assembly/test-assembly.xml      

这是test-assembly.xml的内容

  test-classloader  jar  false   ${project.build.testOutputDirectory} /   com/test/**     

我会尝试在测试中设置测试所需的一切。 主要优点是没有神奇的看不见的设置,这是测试隐含的。 测试可以在每个环境中运行。 此外,添加新的严格隔离的方案要容易得多,因为您不依赖于某些混合方案设置。

设置不应该太难:

  • 序列化一个java类:
    • 使用某些类型代码工程库
    • 或者,使用重命名为.class之外的某个文件后缀的java类文件。 将它放在test资源文件夹下并使用类加载器加载(getResourceAsStream(…))。
  • 压缩类文件(`java.util.zip.GZIPOutputStream`)
  • 使用类加载器加载类文件

有一种替代方法,它使用java类加载器设计并且无需生成其他类即可工作。

Java有一个类加载器层次结构。 每个类加载器都有一个父类加载器。 类加载器层次结构的根是引导类加载器。 当一个类加载一个类加载器时,它将尝试首先使用父类加载器然后自己加载该类。

您可以使用当前的类加载器加载测试类。 将它包装起来并使用您自己的类加载器加载它。 唯一的区别是您将父类加载器设置为无法加载测试类的加载器。

 String resource = My.class.getName().replace(".", "/") + ".class"; //class loader of your test class ClassLoader myClassLoader = currentThread().getContextClassLoader(); assert ! toList(myClassLoader.getResources(resource)).isEmpty(); //just to be sure that the resource cannot be loaded from the parent classloader ClassLoader parentClassloader = getSystemClassLoader().getParent(); assert toList(parentClassloader.getResources(resource)).isEmpty(); //your class loader URLClassLoader myLoader = new URLClassLoader(new URL[0], parentClassloader); assert toList(myLoader.getResources(resource)).isEmpty(); 

Maven通过依赖性分析来解析构建顺序,因此通常您的JAR将按顺序构建,因为使用您的测试JAR的JAR只会将它们声明为依赖项。 但是,依赖关系也放在类路径上。 依赖项的“范围”决定了它继续执行的类路径。 例如,’compile’依赖项在类路径上进行编译,测试和运行; ‘runtime’依赖项在类路径上进行测试和运行; ‘test’依赖项仅在测试期间在类路径上。 不幸的是,你有一个案例没有被任何可用的范围覆盖:你有一个依赖,但你不希望它在类路径上。 这是一个边缘用例,也是您在发现示例时遇到问题的原因。

因此,除非一些Maven大师重新表明相反,否则我建议如果不编写特殊的Maven插件,这是不可能的。 不过,我推荐别的东西。 你真的需要定制的JAR来测试你的类加载器吗? 这对我来说听起来很可疑。 也许你可以使用任何旧的JAR? 如果是这样,我将使用maven-dependency-plugin将一些已知的JAR复制到您的本地模块的目标目录中(例如log4j)。 然后,您的测试可以通过target/log4j-xxx.jar上的文件路径访问该JAR,您可以做任何事情。