Получение "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_();
}