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

233

Я использую 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?

Ноэль Яп
источник

Ответы:

272

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

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

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

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

Гарретт Холл
источник
1
ОП сказал, что они уже использовали банку -dep-. Но ваше предположение, что он использует класс Matcher из JUnit, звучит правильно. Так что, вероятно, IDE использует свою собственную копию JUnit.
MatrixFrog
2
Я удалил копию IntelliJ из junit.jar и junit-4.8.jar, установил junit-dep-4.10.jar в каталог lib / IntelliJ, и проблема все еще возникает.
Ноэль Яп
8
JUnit 4,11 совместим с Hamcrest 1.3 и JUnit 4,10 совместим с Hamcrest 1.1 search.maven.org/remotecontent?filepath=junit/junit-dep/4.10/...
Muthu
23
убедитесь, что вы не используете mockito-all, а вместо этого mockito-core с исключением подколенного сухожилия
Ulf Lindback
1
В офисе 7:33 вечера, я работаю над важной функцией, которую должен предоставить перед выходом в отпуск, и сейчас пятница, я нахожусь в этом отпуске на следующей неделе !!!!!! Как, черт возьми, я мог получить эту ошибку сейчас !!!
Аделин
170

Эта проблема также возникает, когда у вас есть 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>
Том Паркинсон
источник
2
Как новые версии mockito включают в себя Hamcrest так же, как Powermock!
Том Паркинсон
3
Должно ли это быть ядром мокито, а не всем мокито?
user944849
3
Вы можете включить только ядро, если вам это нужно только в ногу со временем, однако вышеприведенное должно работать во всех случаях. Порядок зависимостей - это важный бит mvn 3, который начинается сверху вниз в порядке приоритета.
Том Паркинсон
3
Вы не должны включать mockito-all, поскольку он включает в себя hamcrest 1.1, вместо этого включайте mockito-core и исключайте из него hancrest (чего вы не можете сделать из всех)
Ulf Lindback
1
«Если возможно, просто включите мокито-ядро». Хорошо, тогда почему этот ответ все еще использует mockito-all?
Раввин Стелс
60

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

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

mvn dependency:tree -Dscope=test
Ноэль Яп
источник
5
Я была такая же проблема. Я использовал JUnit-dep и Hamcrest-core, но у меня в списке пометок Powermock, что привело к включению JUnit перед JUnit-dep и Hamcrest.
Джон Б
9
Также mockito-all включает несколько классов Hamcrest. Лучше использовать mockito-core и исключить зависимость от Hamcrest.
Брамбо
3
Просто наткнулся на точно такую ​​же проблему. Решением было повышение версии junit до 4.11, которая совместима (т.е. «содержит классы из») с Hamcrest 1.3
r3mbol
Для тех, у кого не все предложения работали (порядок зависимостей, исключения, удаление, замена -allна -coreи т. Д.): Мне пришлось изменить Hamcrest обратно на версию 1.1, и теперь все работает снова.
Феликс Хагспил
1
для меня это сработало, когда я изменил свой импорт на import static org.mockito.Matchers.anyString;сimport static org.mockito.ArgumentMatchers.anyString;
Шрикант Прабху
28

Следующее должно быть наиболее правильным сегодня. Обратите внимание, что 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>
Ульф Линдбек
источник
3
Обратите внимание, что JUnit 4.12 теперь зависит от ядра Hamcrest 1.3.
JeeBee
Исключение из mockito-allпомогло мне, нет mockito-core. Также объявляет Hamcrest перед Mockito в pom.xmlработах.
Кирилл
13

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

<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>
Raul
источник
Мне то же. Размещение зависимостей в этом порядке помогает maven правильно разрешать переходные операции. Явное исключение подколенного сухожилия из мокито-сердечника или мокито-все может быть более безопасным, в случае, если кто-то изменит порядок deps в вашем pom.
Мат
4

Пытаться

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

вместо того

expectMessage(message)

Вы можете написать собственный ExpectedExceptionили служебный метод для завершения кода.

Цян Ли
источник
4

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

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

Я обнаружил, что проблема была в функции «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));

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

Siro
источник
0

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

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

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

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

Джейсон Д
источник
0

Я знаю, что это не лучший ответ, но если вы не можете заставить работать 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_();
}
Фрэнсис
источник
0

У меня есть проект 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 -все-в-mavengradle основе-проектов /

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

Павел
источник
0

В моем случае мне пришлось исключить более старый подколенный сухожилий из 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>
Андре
источник
0

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