使用Hamcrest 1.3和JUnit 4.11的NoSuchMethodError

另一个JUnit&Hamcrest组合的NoSuchMethodError实例。 出错代码:

 assertThat(dirReader.document(0).getFields(), hasItem( new FeatureMatcher<IndexableField, String>(equalTo("Patisnummer"), "Field key", "Field key") { @Override protected String featureValueOf(IndexableField actual) { return actual.name(); } } )); 

IndexerTest.java中的注释行152-157(commit ac72ce )

导致NoSuchMethodError(请参阅http://db.tt/qkkkTE78获取完整的输出):

 java.lang.NoSuchMethodError: org.hamcrest.Matcher.describeMismatch(Ljava/lang/Object;Lorg/hamcrest/Description;)V at org.hamcrest.FeatureMatcher.matchesSafely(FeatureMatcher.java:43) at org.hamcrest.TypeSafeDiagnosingMatcher.matches(TypeSafeDiagnosingMatcher.java:55) at org.hamcrest.core.IsCollectionContaining.matchesSafely(IsCollectionContaining.java:25) at org.hamcrest.core.IsCollectionContaining.matchesSafely(IsCollectionContaining.java:14) at org.hamcrest.TypeSafeDiagnosingMatcher.matches(TypeSafeDiagnosingMatcher.java:55) at org.junit.Assert.assertThat(Assert.java:770) at org.junit.Assert.assertThat(Assert.java:736) at indexer.IndexerTest.testIndexContainsField(IndexerTest.java:152) 

设置:

  • JUnit 4.11
  • Hamcrest 1.3
  • 使用Maven的surefire插件(版本2.14),它使用了JUnitCoreProvider
  • Java 7(OpenJDK)
  • 看到pom (commit ac72ce )

背景:

NoSuchMethodError是由调用非现有方法的(编译)类引起的。 describeMismatch和JUnit + Hamcrest组合的具体情况通常是由JUnit中包含的Hamcrest类与Hamcrest类库中这些类的版本之间的不兼容造成的。

尝试解决NoSuchMethodError:

  • pom包含Hamrerest-Library 1.3,Hamcrest-core 1.3和JUnit 4.11的显式依赖,正如Garrett Hall在回答 在运行testing时得到“NoSuchMethodError:org.hamcrest.Matcher.describeMismatch” (按照该顺序) IntelliJ 10.5

  • 根据JUnit文档,JUnit 4.11 Maven依赖不再包含已编译的Hamcrest类,而是依赖于Hamcrest核心1.3; 所以NoSuchMethodError不应该发生。

  • 使用mvn dependency:tree检查依赖关系树mvn dependency:tree Dan在回答 junit和hamcrest声明时提供的 mvn dependency:tree显示了对Hamcrest 1.3和JUnit 4.11的显式依赖关系,而对这些文件没有其他依赖关系(请参阅http://db.tt/C2OfTDJB完成输出)。

  • 在另一个testing中,使用下面的方法避免了NoSuchMethodError

     assertThat( "Zylab detector not available", d.getDetectors(), hasItem(Matchers.<Detector>instanceOf(ZylabMetadataXmlDetector.class))); 

    在IndexerTest.java的第120-123 行 (commit ac72ce )而不是更明显的:

     assertThat( "Zylab detector not available", d.getDetectors(), hasItem(isA(ZylabMetadataDetector.class)); 

    我不确定是否显式types参数<Detector> ,使用instanceOf而不是isA ,显式引用Hamcrest的Matchers ,或者避免了NoSuchMethodException的组合; 经过摆弄,尝试不同的事情。

  • 使用显式types参数不能解决/避免错误。

  • 使用派生自BaseMatcher而不是FeatureMatcher的类没有解决/避免错误。

想法如何修复NoSuchMethodError

这个博客帮助我解决了同样的问题:

https://tedvinke.wordpress.com/2013/12/17/mixing-junit-hamcrest-and-mockito-explaining-nosuchmethoderror/

在Mockito和Junit的依赖关系中,作者增加了排除:

 <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.11</version> <exclusions> <exclusion> <artifactId>hamcrest-core</artifactId> <groupId>org.hamcrest</groupId> </exclusion> </exclusions> </dependency> 

也许这些其他JAR中有一个是Hamcrest的MatcherBaseMatcher老版本。 下面是包含后者的JAR列表 ,但我不知道该网站有多全面。 有没有一个Maven插件,它会告诉你所有的依赖关系,包括类依赖树的类?

如果您使用Eclipse,“打开types”工具(CTRL + SHIFT + T)可以帮助您find有问题的软件包。 只要search类名(例如Description),来自不同JAR的同一类的多次出现就是红旗。

对我有用的是重新sorting依赖关系。 而不是去mockito,junit,我必须把junit,mockito。

Mockito 1.9.5使用hamcrest 1.1,这是不兼容的,导致问题。

使用David的技巧,以及如何在Bash中的分隔符上分割string? 导致下面的bash脚本:

 ( IFS=":"; for i in `mvn dependency:build-classpath | grep -v '\[INFO\]'`; do jar tf $i | awk "{print \"$i\\t\" \$1}"; done | grep Matcher ) 

(在线http://www.kaspervandenberg.net/2013/scripts/findDependencyClass.sh

其中发现依赖JGlobus-Core-2.0.4有它自己的版本的org.hamcrest.BaseMatcherorg.hamcrest.CoreMatchersorg.hamcrest.Matcher

如果你正在使用Eclipse:对于我来说,在eclipse-> project properties-> Java build Path将mockito-all-1.9.5.jar移动到“Order and Export”列表的底部。 刚刚上面,我有junit-4.11.jar和以上那hamcrest-core-1.3.jar

我用下面的代码在我的Gradle项目中解决了这个jar hell问题:

  testCompile (group: 'junit', name: 'junit', version: '4+') { exclude group: 'org.hamcrest' } testCompile ('org.mockito:mockito-core:1+') { exclude group: 'org.hamcrest' } testCompile 'org.hamcrest:java-hamcrest:2.0.0.0' 

对于使用Gradle作为构build工具的项目:

 testCompile("junit:junit:4.11") { exclude group: 'org.hamcrest', module: 'hamcrest-core' exclude group: 'org.hamcrest', module: 'hamcrest-library' } testCompile group: 'org.hamcrest', name: 'hamcrest-core', version: '1.3' testCompile group: 'org.hamcrest', name: 'hamcrest-library', version: '1.3'