Получение "NoSuchMethodError: org.hamcrest.Matcher.describeMismatch" при запуске теста в IntelliJ 10.5

Я использую 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, единственные банки подколенного сухожилия в моем классе - 1.3.RC2.

Использует ли IntelliJ IDEA собственную копию JUnit или Hamcrest?

Как вывести время выполнения CLASSPATH, которое использует IntelliJ?

15 ответов

Решение

Проблема заключалась в том, что неправильно hamcrest.Matcherне hamcrest.MatcherAssertКласс использовался. Это было извлечено из зависимости от junit-4.8, которую указывал одна из моих зависимостей.

Чтобы увидеть, какие зависимости (и версии) включены из какого источника во время тестирования, запустите:

mvn dependency:tree -Dscope=test

Убедитесь, что банка подколенного сухожилия выше в порядке импорта, чем банка JUnit.

JUnit поставляется со своим org.hamcrest.Matcher класс, который, вероятно, используется вместо этого.

Вы также можете скачать и использовать junit-dep-4.10.jar, который является JUnit без классов hamcrest.

В mockito также есть классы хамкрестов, так что вам может понадобиться переместить \ переупорядочить их

Эта проблема также возникает, когда у вас есть mockito-all на пути к классам, что уже устарело.

Если возможно, просто включите мокито-ядро.

Конфигурация 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>

Следующее должно быть наиболее правильным сегодня. Обратите внимание, что junit 4.11 зависит от ядра Hamcrest, поэтому вам не нужно указывать, что 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>

Это сработало для меня после небольшой борьбы

<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>

Я знаю, что это старая ветка, но что решило проблему для меня, так это добавив следующее в мои файлы 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'

Пытаться

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

вместо

expectMessage(message)

Вы можете написать кастом ExpectedException или служебный метод, чтобы обернуть код.

По состоянию на июль 2020 года у меня работали следующие зависимости в 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>

С этой библиотекой junit 4.13 и hamcrest он использует hamcrest.MatcherAssert при утверждении и генерирует исключение -введите описание изображения здесь

У меня есть проект 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-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, кроме самого 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, что позволяет обнаруживать возможную несовместимость версий с инструментами анализа зависимостей. Это гораздо лучшее решение, когда в проекте используется инструмент управления зависимостями.

Несмотря на то, что это очень старый вопрос, и, вероятно, многие из вышеупомянутых идей решили многие проблемы, я все же хочу поделиться этим решением с сообществом, которое решило мою проблему.

Я обнаружил, что проблема заключалась в функции с именем "hasItem", которую я использовал, чтобы проверить, содержит ли JSON-Array определенный элемент. В моем случае я проверил значение типа Long.

И это привело к проблеме.

Почему-то у Matchers возникают проблемы со значениями типа Long. (Я не использую JUnit или Rest-Assured, поэтому idk. Именно поэтому, но я предполагаю, что возвращаемые JSON-данные содержат только целые числа.)

Итак, что я сделал, чтобы решить проблему, так это следующее. Вместо того, чтобы использовать:

long ID = ...;

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

Вы просто должны привести к Integer. Итак, рабочий код выглядел так:

long ID = ...;

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

Возможно, это не лучшее решение, но я просто хотел упомянуть, что исключение также может быть вызвано из-за неправильных / неизвестных типов данных.

В моем случае я должен был исключить старый хемкрест из junit-vintage:

<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>

Это сработало для меня. Не нужно ничего исключать. Я просто использовалmockito-core вместо mockito-all

testCompile 'junit:junit:4.12'
testCompile group: 'org.mockito', name: 'mockito-core', version: '3.0.0'
testCompile group: 'org.hamcrest', name: 'hamcrest-library', version: '2.1'

Для jUnit 4.12 следующая комбинация зависимостей устранила мою проблему.

      <dependency>
   <groupId>junit</groupId>
   <artifactId>junit</artifactId>
   <version>4.12</version>
   <scope>test</scope>
</dependency>
<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>

Для меня сработало исключение группы hamcrest из тестовой компиляции junit.

Вот код из моего build.gradle:

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

Если вы используете IntelliJ, вам может понадобиться запустить gradle cleanIdea idea clean build снова обнаружить зависимости.

Я знаю, что это не лучший ответ, но если вы не можете заставить работать classpath, это решение плана B.

В моем тестовом пути к классам я добавил следующий интерфейс с реализацией по умолчанию для метода descriptionMismatch.

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_();
}
Другие вопросы по тегам