JUnitMatchers.containsString 的静态导入有效,但 CoreMatchers.containsString 无效

Static import of JUnitMatchers.containsString works but not CoreMatchers.containsString

我有相当庞大的代码库。其中一项测试 类 正在使用导入语句,该语句在以下静态导入的编译过程中失败。它在导入语句以及对 constainsString() 的实际调用位置失败。

import static org.hamcrest.CoreMatchers.containsString;

具体错误如下:

[ERROR] MyClassName:[...] error: cannot find symbol
[ERROR] symbol:   method containsString(String)
[ERROR] location: class MyClassName

将上述静态导入更改为 JUnitMatchers.containsString 修复了问题:

import static org.junit.matchers.JUnitMatchers.containsString;

我的有效 pom.xml 具有以下相关依赖项:

junit:jUnit:4.11
org.hamcrest:hamcrest-all:1.1
org.mockito:mockito-all:1.9.5

所以,问题确实是

  1. 为什么 JUnitMatchers.containsString 是成功的,而实际上它已被弃用,取而代之的是 CoreMatchers.containsString?
  2. 如果它选择了任何库的错误版本,我们如何让 Maven 使用正确的版本?

Hamcrest 1.1 没有 containsString 方法。无法找到源代码(显然,根据 comment on this commit,之前正在生成 class),但我们可以使用反编译的 class:

public class CoreMatchers {
    public static <T> Matcher<T> is(Matcher<T> matcher) {
        return Is.is(matcher);
    }

    public static <T> Matcher<T> is(T value) {
        return Is.is(value);
    }

    public static Matcher<Object> is(Class<?> type) {
        return Is.is(type);
    }

    public static <T> Matcher<T> not(Matcher<T> matcher) {
        return IsNot.not(matcher);
    }

    public static <T> Matcher<T> not(T value) {
        return IsNot.not(value);
    }

    public static <T> Matcher<T> equalTo(T operand) {
        return IsEqual.equalTo(operand);
    }

    public static Matcher<Object> instanceOf(Class<?> type) {
        return IsInstanceOf.instanceOf(type);
    }

    public static <T> Matcher<T> allOf(Matcher... matchers) {
        return AllOf.allOf(matchers);
    }

    public static <T> Matcher<T> allOf(Iterable<Matcher<? extends T>> matchers) {
        return AllOf.allOf(matchers);
    }

    public static <T> Matcher<T> anyOf(Matcher... matchers) {
        return AnyOf.anyOf(matchers);
    }

    public static <T> Matcher<T> anyOf(Iterable<Matcher<? extends T>> matchers) {
        return AnyOf.anyOf(matchers);
    }

    public static <T> Matcher<T> sameInstance(T object) {
        return IsSame.sameInstance(object);
    }

    public static <T> Matcher<T> anything() {
        return IsAnything.anything();
    }

    public static <T> Matcher<T> anything(String description) {
        return IsAnything.anything(description);
    }

    public static <T> Matcher<T> any(Class<T> type) {
        return IsAnything.any(type);
    }

    public static <T> Matcher<T> nullValue() {
        return IsNull.nullValue();
    }

    public static <T> Matcher<T> nullValue(Class<T> type) {
        return IsNull.nullValue(type);
    }

    public static <T> Matcher<T> notNullValue() {
        return IsNull.notNullValue();
    }

    public static <T> Matcher<T> notNullValue(Class<T> type) {
        return IsNull.notNullValue(type);
    }

    public static <T> Matcher<T> describedAs(String description, Matcher<T> matcher, Object... values) {
        return DescribedAs.describedAs(description, matcher, values);
    }
}

在中央仓库中找不到 1.2 版,but 1.3 确实定义了该方法(以及其他一些方法)。

JUnit 4.11(以及 4.12)已经引用了 Hamcrest 1.3,但是 mockito-1.9.5 references v1.1(滚动到依赖项)。您也可以通过 运行 mvn dependency:tree:

查看
[INFO] \- org.mockito:mockito-core:jar:1.9.5:compile
[INFO]    +- org.hamcrest:hamcrest-core:jar:1.1:compile
[INFO]    \- org.objenesis:objenesis:jar:1.0:compile

---------------

[INFO] +- junit:junit:jar:4.11:compile
[INFO] |  \- org.hamcrest:hamcrest-core:jar:1.3:compile

没有看到实际的 pom,我不能说如何,但不知何故 v1.1 优先于 1.3,或者明确地,或者 mockito 可能在 junit 之前在你的 pom 中声明。因此,您可以尝试在您的 pom 中交换 junit 和 mockito 顺序,或者直接明确定义 Hamcrest 1.3 以 override 传递版本:

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