Maven Surefire测试中的ClassNotFoundExceptions

时间:2016-05-10 15:10:08

标签: java maven classpath surefire

在Maven Surefire中执行测试时,我不时会看到ClassNotFoundException

这真让我头疼,因为:

  • 缺少的班级各不相同。只有大约5个类受到影响,但是从构建到构建都会受到影响。但是,我发现这些类之间没有独特的相似之处,他们不会与其他20个同类的类共享。
  • 这些缺失的类来自2个不同的依赖项。当然,这些都是由Maven管理的。
  • CNFE被提升时,我看了一下类路径(在运行时!),它看起来很好!

我如何分析类路径

我从Arno Haase那里获取了"class path scanner"的代码:

public List<URL> getRootUrls () {
  List<URL> result = new ArrayList<> ();

  ClassLoader cl = Thread.currentThread().getContextClassLoader();
  while (cl != null) {
    if (cl instanceof URLClassLoader) {
      URL[] urls = ((URLClassLoader) cl).getURLs();
      result.addAll (Arrays.asList (urls));
    }
    cl = cl.getParent();
  }
  return result;
}

网址列表很短:

  • 一些JRE库
  • 一个“surefire booter jar”

后一个jar将我的所有Maven依赖项捆绑在其清单文件as described in the Surefire docs.

所以我进一步挖掘并分析了清单的“Class-Path”属性。在那里,我发现列出了依赖jar,缺少的类应该来自哪里。 浏览jar的条目时,我还在那里找到了缺少的课程。完全限定的路径也匹配。

所以原则上一切似乎都是正确的。 我现在应该继续调查哪些内容?

1 个答案:

答案 0 :(得分:1)

有几件事要检查这些问题。

  • 这是通过命令行还是仅通过CI构建发生的?如果使用Jenkins或Hudson,这是一个Maven项目还是带有Maven构建步骤的FreeStyle项目?如果这是一个Maven项目,请将其切换到带有Maven构建步骤的FreeStyle项目,这样就可以解决问题。 Maven团队的Stephen Connolly考虑Jenkins Maven build type evil
  • 确保每个依赖项只有一个版本,并且相关的依赖项(Spring,ASM,Hibernate等)具有相同/兼容的版本。特别注意组ID或工件ID已更改的工件,例如spring.jarspring-core.jar。开始使用旧的Tattletale plugin可能很有用。
  • 将以-all结尾的所有依赖项替换为其组成部分。 -all jar可能包含运行库所需的每个类 - 重新打包到Maven的依赖解析过程无法获取的jar文件中 - 而不是将它们作为依赖项引用。 mockito-all,hamcrest-all,powermock-all,cglib就是例子。
  • 如果使用覆盖工具(Jacoco,Clover),如果关闭覆盖范围,构建是否有效?如果是,该工具可能会引入与您的应用程序冲突的类路径jar。 (例如,不同版本的CGLIB。)在调试模式下运行并比较具有/不具有覆盖的依赖性以识别差异。
  • 如果使用JUnit,请确保Maven surefire正在为您的JUnit版本使用正确的JUnit提供程序。使用-X在调试模式下运行构建(如果使用命令行,则将输出重定向到文件)。 Grep surefire-junit的输出。你应该找到这样的东西:

    [DEBUG] org.apache.maven.surefire:surefire-junit4:jar:2.16:test(选择进行测试)

    现在,确保提供程序的版本与使用的JUnit版本匹配。查看Maven docs,了解有关使用哪个提供商以及如何配置的信息。