【问题标题】:Using Maven to build separate JAR files for unit testing a custom class loader使用 Maven 构建单独的 JAR 文件以对自定义类加载器进行单元测试
【发布时间】:2010-11-26 23:24:39
【问题描述】:

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

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

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

【问题讨论】:

  • 不确定我是否理解这个问题。您想在执行测试之前从某些特定的测试类创建一个 jar 吗?
  • 您的测试不完全是单元测试。它不测试一个孤立的单元,而是测试多个单元的集成(你的类加载器、java 类加载器、文件 io)。
  • 您可以添加测试和集成测试以获得更多回复。

标签: java unit-testing maven-2 integration-testing


【解决方案1】:

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

设置不应该太难:

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

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

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

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

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();

【讨论】:

  • 我提供了一个答案,但如果问题的约束可以放松,我更喜欢这个。
  • 如果您愿意,甚至可以使用扩展 GZIPOutputStream 类的 JarOutputStream 创建一个 jar。
  • 有什么区别?清单支持?
【解决方案2】:

最简单的做法是设置另一个项目来为您的测试 jar 打包类,然后将其设置为普通的 test-scoped 依赖项。

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

程序集插件使用一个程序集描述符(在 src/main/assembly,称为 test-assembly.xml),它封装了目标/测试类的内容。我设置了一个过滤器来包含 com.test 包及其子包的内容。这假设您有一些包名称约定,您可以为 jar 的内容申请。

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

<plugin>
  <artifactId>maven-assembly-plugin</artifactId>
  <version>2.2-beta-2</version>
  <executions>
    <execution>
      <id>create-test-dependency</id>
      <phase>process-test-classes</phase>
      <goals>
        <goal>single</goal>
      </goals>
      <configuration>
        <finalName>classloader-test-deps</finalName>
        <attach>false</attach>
        <descriptors>
          <descriptor>src/main/assembly/test-assembly.xml</descriptor>
        </descriptors>
      </configuration>
    </execution>
  </executions>
</plugin>

这是test-assembly.xml的内容

<assembly>
  <id>test-classloader</id>
  <formats>
    <format>jar</format>
  </formats>
  <includeBaseDirectory>false</includeBaseDirectory>
  <fileSets>
    <fileSet>
      <directory>${project.build.testOutputDirectory}</directory>
      <outputDirectory>/</outputDirectory>
      <!--modify/add include to match your package(s) -->
      <includes>
        <include>com/test/**</include>
      </includes>
    </fileSet>
  </fileSets>
</assembly>

【讨论】:

  • 适当的依赖关系确实是测试范围的。您建议的汇编插件方法有希望。我会试一试!
  • 富卖家:这两个答案都被证明是正确的。由于我自己的一些愚蠢,我设法巧妙地破坏了 POM 以生成测试 jar。一旦修复,测试范围按预期工作,尽管 Maven 给我的线索使修复变得非常困难。我还试用了汇编插件,效果也不错。它的灵活性在更复杂的情况下可能非常有用。
【解决方案3】:

Maven 通过依赖分析解析构建顺序,所以通常你的 JAR 会按顺序构建,因为使用你的测试 JAR 的那个会简单地将它们声明为依赖。但是,依赖项也放置在类路径上。依赖项的“范围”决定了它继续使用哪个类路径。例如,“编译”依赖项位于用于编译、测试和运行的类路径上; “运行时”依赖项位于用于测试和运行的类路径上; “测试”依赖项仅在测试期间位于类路径上。不幸的是,您有一个任何可用范围都没有涵盖的案例:您有一个依赖项,但您不希望它出现在类路径中。这是一个边缘用例,这就是您在发现示例时遇到困难的原因。

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

【讨论】:

  • 我真的需要特殊的罐子。这些测试旨在显示对我们正在实现的插件架构的特定模式的支持(对于像 OSGi 这样的东西来说太简单了)。 “标准”罐子不适合这种模式,AFAIK。
猜你喜欢
  • 2023-03-29
  • 1970-01-01
  • 1970-01-01
  • 2017-04-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-06-09
  • 2016-07-09
相关资源
最近更新 更多