在IntelliJ 10.5中运行测试时出现“NoSuchMethodError: org.hamcrest.Matcher.describeMismatch”的错误。

245

我正在使用JUnit-dep 4.10和Hamcrest 1.3.RC2。

我创建了一个自定义匹配器,看起来像下面这样:

public static class MyMatcher extends TypeSafeMatcher<String> {
    @Override
    protected boolean matchesSafely(String s) {
        /* implementation */
    }

    @Override
    public void describeTo(Description description) {
        /* implementation */
    }

    @Override
    protected void describeMismatchSafely(String item, Description mismatchDescription) {

        /* implementation */
    }
}

在使用Ant命令行运行时,它完美地工作。但是在使用IntelliJ运行时,它会失败,显示以下错误:

java.lang.NoSuchMethodError: org.hamcrest.Matcher.describeMismatch(Ljava/lang/Object;Lorg/hamcrest/Description;)V
    at org.hamcrest.MatcherAssert.assertThat(MatcherAssert.java:18)
    at org.hamcrest.MatcherAssert.assertThat(MatcherAssert.java:8)
    at com.netflix.build.MyTest.testmyStuff(MyTest.java:40)

我猜测它正在使用错误的 hamcrest.MatcherAssert。 我如何找出它正在使用哪个 hamcrest.MatcherAssert(即哪个 jar 文件用于 hamcrest.MatcherAssert)? 据我所知,我的类路径中唯一的 hamcrest jars 是 1.3.RC2。

IntelliJ IDEA 是否在使用自己的 JUnit 或 Hamcrest 副本?

如何输出 IntelliJ 正在使用的运行时 CLASSPATH?

15个回答

281

请确保在导入顺序中hamcrest jar的优先级高于您的JUnit jar。

JUnit自带其自己的org.hamcrest.Matcher类,可能正在使用它。

您也可以下载并使用junit-dep-4.10.jar代替,它是不包含hamcrest类的JUnit。

mockito中也包含了hamcrest类,因此您可能需要移动/重新排序它们。


2
我刪除了IntelliJ的 junit.jar 和 junit-4.8.jar,並將 junit-dep-4.10.jar 安裝到 IntelliJ 的 lib/ 目錄中,但問題仍然存在。 - Noel Yap
8
JUnit 4.11兼容Hamcrest 1.3,而JUnit 4.10兼容Hamcrest 1.1。http://search.maven.org/remotecontent?filepath=junit/junit-dep/4.10/junit-dep-4.10.pom - Muthu
25
请确保您没有使用mockito-all,而是使用带有hamcrest排除的mockito-core。 - Ulf Lindback
1
现在是晚上7:33,我正在办公室工作,处理一个重要的功能,在我去度假之前必须完成。而且今天是星期五,下周我就要开始度假了!!!怎么会出现这个错误啊!!! - Adelin
2
“higher on the import” 是什么意思? - Adelin
显示剩余7条评论

180

当你的类路径上已经有mockito-all时,这个问题也会出现,而该依赖项已被弃用。

如果可能的话,请仅包括mockito-core

Maven配置以混合使用junit、mockito和hamcrest:

<dependencies>
  <dependency>
    <groupId>org.hamcrest</groupId>
    <artifactId>hamcrest-core</artifactId>
    <version>1.3</version>
    <scope>test</scope>
  </dependency>
  <dependency>
    <groupId>org.hamcrest</groupId>
    <artifactId>hamcrest-library</artifactId>
    <version>1.3</version>
    <scope>test</scope>
  </dependency>
  <dependency>
    <groupId>org.mockito</groupId>
    <artifactId>mockito-all</artifactId>
    <version>1.9.5</version>
    <scope>test</scope>
  </dependency>
  <dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <version>4.11</version>
    <scope>test</scope>
  </dependency>
</dependencies>

这正是我需要的提示。简单来说,就是检查所有这些超级JAR包中是否存在隐藏的依赖关系。或者更好的方法是不要懒惰,干脆不使用它们。 - Oliver
2
新版本的Mockito包含了Hamcrest,而Powermock也是如此! - Tom
3
是不是应该使用mockito-core而不是mockito-all? - user944849
3
如果只需要核心内容,可以仅包含核心部分,但上述内容在所有情况下都应当可行。依赖关系的顺序是重要的,mvn 3 会按照优先级从上到下开始执行。 - Tom
3
不应包含mockito-all,因为其中包含hamcrest 1.1版本。相反,应该包含mockito-core并从中排除hamcrest(这不能从all中完成)。 - Ulf Lindback
2
如果可能的话,只需包含mockito-core。那么,为什么这个答案仍然使用mockito-all呢? - Stealth Rabbi

63

问题在于使用了错误的hamcrest.Matcher类,而不是hamcrest.MatcherAssert类。这是由我其中一个依赖项指定的junit-4.8依赖项引入的。

要查看测试时包含了哪些来源的依赖项(及其版本),请运行:

mvn dependency:tree -Dscope=test

5
我遇到了相同的问题。我使用了JUnit-dep和Hamcrest-core,但是我在pom文件中将Powermock列在了更早的位置,这导致JUnit在JUnit-dep和Hamcrest之前被包含进来。 - John B
9
Mockito-all 包含一些 Hamcrest 类。最好使用 mockito-core 并排除 hamcrest 依赖。 - Brambo
3
刚刚遇到了完全相同的问题。解决方法是将 junit 版本升级至 4.11,该版本与 hamcrest 1.3 兼容(即“包含”来自该版本的类)。 - r3mbol
对于那些所有建议都不起作用的人(依赖顺序、排除、将“-all”替换为“-core”等):我不得不将hamcrest改回1.1版本,现在一切都正常了。 - Felix Hagspiel
2
对我而言,当我将我的导入更改为 import static org.mockito.Matchers.anyString; 而不是 import static org.mockito.ArgumentMatchers.anyString; 时,它起作用了。 - Shrikant Prabhu

29
以下应该是最正确的。注意,junit 4.11 依赖于 hamcrest-core,因此你根本不需要指定它,mockito-all 不能使用,因为它包含(而不是依赖于)hamcrest 1.1。
<dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <version>4.11</version>
    <scope>test</scope>
</dependency>
<dependency>
    <groupId>org.mockito</groupId>
    <artifactId>mockito-core</artifactId>
    <version>1.10.8</version>
    <scope>test</scope>
    <exclusions>
        <exclusion>
            <groupId>org.hamcrest</groupId>
            <artifactId>hamcrest-core</artifactId>
        </exclusion>
    </exclusions>
</dependency>

3
请注意,JUnit 4.12 现在依赖于 hamcrest-core 1.3。 - JeeBee
从“mockito-all”中排除对我有帮助,而不是“mockito-core”。在“pom.xml”中先声明Hamcrest再声明Mockito也可以起作用。 - Kirill

17

在一番努力后,这对我起了作用。

<dependency>
    <groupId>org.hamcrest</groupId>
    <artifactId>hamcrest-all</artifactId>
    <version>1.3</version>
    <scope>test</scope>
 </dependency>

 <dependency>
    <groupId>org.mockito</groupId>
    <artifactId>mockito-all</artifactId>
    <version>1.9.5</version>
    <scope>test</scope>
 </dependency>

 <dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <version>4.11</version>
    <scope>test</scope>
 </dependency>

对我来说也是一样。按照这个顺序放置依赖项可以帮助Maven正确解析传递依赖项。不过,从mockito-core或mockito-all中显式排除hamcrest可能更安全,以防万一有人重新排列了您的pom中的依赖项。 - Mat

5

我知道这是一个旧的线程,但解决我的问题的方法是将以下内容添加到我的 build.gradle 文件中。

正如上面已经提到的,mockito-all 存在与其他库的兼容性问题。

可能有用的帖子

testCompile ('junit:junit:4.12') {
    exclude group: 'org.hamcrest'
}
testCompile ('org.mockito:mockito-core:1.10.19') {
    exclude group: 'org.hamcrest'
}
testCompile 'org.hamcrest:hamcrest-core:1.3'

4

尝试使用

expect(new ThrowableMessageMatcher(new StringContains(message)))

代替

expectMessage(message)

您可以编写自定义的ExpectedException或实用方法来包装代码。


2

我有一个Gradle项目,当我的build.gradle依赖部分看起来像这样:

dependencies {
    implementation group: 'org.apache.commons', name: 'commons-lang3', version: '3.8.1'

    testImplementation group: 'org.mockito', name: 'mockito-all', version: '1.10.19'
    testImplementation 'junit:junit:4.12'
//    testCompile group: 'org.mockito', name: 'mockito-core', version: '2.23.4'

    compileOnly 'org.projectlombok:lombok:1.18.4'
    apt 'org.projectlombok:lombok:1.18.4'
}

它导致了这个异常:

java.lang.NoSuchMethodError: org.hamcrest.Matcher.describeMismatch(Ljava/lang/Object;Lorg/hamcrest/Description;)V

    at org.hamcrest.MatcherAssert.assertThat(MatcherAssert.java:18)
    at org.hamcrest.MatcherAssert.assertThat(MatcherAssert.java:8)

为了解决这个问题,我已经用“mockito-core”代替了“mockito-all”。
dependencies {
    implementation group: 'org.apache.commons', name: 'commons-lang3', version: '3.8.1'

//    testImplementation group: 'org.mockito', name: 'mockito-all', version: '1.10.19'
    testImplementation 'junit:junit:4.12'
    testCompile group: 'org.mockito', name: 'mockito-core', version: '2.23.4'

    compileOnly 'org.projectlombok:lombok:1.18.4'
    apt 'org.projectlombok:lombok:1.18.4'
}

关于mockito-allmockito-core之间的解释可以在这里找到: https://solidsoft.wordpress.com/2012/09/11/beyond-the-mockito-refcard-part-3-mockito-core-vs-mockito-all-in-mavengradle-based-projects/

mockito-all.jar除了Mockito本身之外,还包含(截至1.9.5)两个依赖项:Hamcrest和Objenesis(让我们暂时忽略重新打包的ASM和CGLIB)。原因是将所有所需内容放在一个JAR文件中,只需将其放在类路径上即可。这可能看起来很奇怪,但请记住,Mockito的开发始于纯Ant(没有依赖管理)是Java项目最流行的构建系统的时代,并且项目所需的所有外部JAR(即我们项目的依赖项及其依赖项)必须手动下载并在构建脚本中指定。
另一方面,mockito-core.jar只是Mockito类(也包括重新打包的ASM和CGLIB)。当使用Maven或Gradle与其配合使用时,所需的依赖关系(Hamcrest和Objenesis)由这些工具进行管理(自动下载并放置在测试类路径上)。它允许覆盖使用的版本(例如,如果我们的项目从未使用过,但向后兼容的版本),但更重要的是,这些依赖关系不会隐藏在mockito-all.jar中,这允许检测到可能存在的版本不兼容性与依赖分析工具。当在项目中使用依赖关系管理工具时,这是更好的解决方案。

2
截至2020年7月,以下pom.xml中的依赖项对我有效:
<dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <version>4.13</version>
</dependency>
<dependency>
    <groupId>org.hamcrest</groupId>
    <artifactId>hamcrest</artifactId>
    <version>2.1</version>
</dependency>

使用4.13版本的junit库和hamcrest,当进行断言并且需要抛出异常时,使用hamcrest.MatcherAssert-

查看图片描述

1
尽管这是一个非常老的问题,可能许多之前提到的想法已经解决了很多问题,但我仍然希望与社区分享解决我的问题的解决方案。
我发现问题出在一个名为“hasItem”的函数上,我使用它来检查JSON-Array是否包含特定项。在我的情况下,我检查了一个Long类型的值。
而这就导致了问题。
不知何故,匹配器对Long类型的值有问题。(我并不经常使用JUnit或Rest-Assured,所以我不确定具体原因,但我猜返回的JSON数据只包含整数。)
因此,我实际上解决问题的方法如下。不要使用:
long ID = ...;

...
.then().assertThat()
  .body("myArray", hasItem(ID));

你只需要将其转换为整数类型(Integer)。 因此,可行的代码看起来像这样:

long ID = ...;

...
.then().assertThat()
  .body("myArray", hasItem((int) ID));

那可能不是最好的解决方案,但我想提一下,异常也可能是由于错误/未知的数据类型而引发的。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接