我使用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)?AFAICT,我的类路径中唯一的hamcrest jars是1.3.RC2。

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

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


当前回答

我知道这不是最好的答案,但是如果您不能让类路径工作,这是一个B计划解决方案。

在我的测试类路径中,我为descripbemismatch方法添加了一个默认实现的接口。

package org.hamcrest;

/**
 * PATCH because there's something wrong with the classpath. Hamcrest should be higher than Mockito so that the BaseMatcher
 * implements the describeMismatch method, but it doesn't work for me. 
 */
public interface Matcher<T> extends SelfDescribing {

    boolean matches(Object item);

    default void describeMismatch(Object item, Description mismatchDescription) {
        mismatchDescription.appendDescriptionOf(this).appendValue(item);
    }

    @Deprecated
    void _dont_implement_Matcher___instead_extend_BaseMatcher_();
}

其他回答

我知道这不是最好的答案,但是如果您不能让类路径工作,这是一个B计划解决方案。

在我的测试类路径中,我为descripbemismatch方法添加了一个默认实现的接口。

package org.hamcrest;

/**
 * PATCH because there's something wrong with the classpath. Hamcrest should be higher than Mockito so that the BaseMatcher
 * implements the describeMismatch method, but it doesn't work for me. 
 */
public interface Matcher<T> extends SelfDescribing {

    boolean matches(Object item);

    default void describeMismatch(Object item, Description mismatchDescription) {
        mismatchDescription.appendDescriptionOf(this).appendValue(item);
    }

    @Deprecated
    void _dont_implement_Matcher___instead_extend_BaseMatcher_();
}

对我来说,有效的方法是从junit测试编译中排除hamcrest组。

下面是build.gradle的代码:

testCompile ('junit:junit:4.11') {
    exclude group: 'org.hamcrest'
}

如果你正在运行IntelliJ,你可能需要运行gradle cleanIdea idea clean build来再次检测依赖项。

截至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 在这里输入图像描述

就我而言,我不得不从junit-vintage中剔除一个更老的hamcrest:

<dependency>
  <groupId>org.junit.vintage</groupId>
  <artifactId>junit-vintage-engine</artifactId>
  <scope>test</scope>
  <exclusions>
    <exclusion>
      <groupId>org.hamcrest</groupId>
      <artifactId>hamcrest-core</artifactId>
    </exclusion>
  </exclusions>
</dependency>
<dependency>
  <groupId>org.hamcrest</groupId>
  <artifactId>hamcrest</artifactId>
  <version>2.1</version>
  <scope>test</scope>
</dependency>

我有一个gradle项目,当我建立。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-all”替换为“mockito-core”。

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-all和mockito-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 besides Mockito itself contains also (as of 1.9.5) two dependencies: Hamcrest and Objenesis (let’s omit repackaged ASM and CGLIB for a moment). The reason was to have everything what is needed inside an one JAR to just put it on a classpath. It can look strange, but please remember than Mockito development started in times when pure Ant (without dependency management) was the most popular build system for Java projects and the all external JARs required by a project (i.e. our project’s dependencies and their dependencies) had to be downloaded manually and specified in a build script. On the other hand mockito-core.jar is just Mockito classes (also with repackaged ASM and CGLIB). When using it with Maven or Gradle required dependencies (Hamcrest and Objenesis) are managed by those tools (downloaded automatically and put on a test classpath). It allows to override used versions (for example if our projects uses never, but backward compatible version), but what is more important those dependencies are not hidden inside mockito-all.jar what allows to detected possible version incompatibility with dependency analyze tools. This is much better solution when dependency managed tool is used in a project.