NoSuchMethodError с Hamcrest 1.3 и JUnit 4.11

Еще один пример NoSuchMethodError для комбинации JUnit & Hamcrest. Оскорбительный код:

assertThat(dirReader.document(0).getFields(), hasItem(
    new FeatureMatcher<IndexableField, String>(equalTo("Patisnummer"), "Field key", "Field key") {
        @Override
        protected String featureValueOf(IndexableField actual) {
            return actual.name();
        } } ));

Комментированные строки 152–157 в IndexerTest.java (commit ac72ce)

Вызывает NoSuchMethodError (полный вывод см. Http://db.tt/qkkkTE78):

java.lang.NoSuchMethodError: org.hamcrest.Matcher.describeMismatch(Ljava/lang/Object;Lorg/hamcrest/Description;)V
at org.hamcrest.FeatureMatcher.matchesSafely(FeatureMatcher.java:43)
at org.hamcrest.TypeSafeDiagnosingMatcher.matches(TypeSafeDiagnosingMatcher.java:55)
at org.hamcrest.core.IsCollectionContaining.matchesSafely(IsCollectionContaining.java:25)
at org.hamcrest.core.IsCollectionContaining.matchesSafely(IsCollectionContaining.java:14)
at org.hamcrest.TypeSafeDiagnosingMatcher.matches(TypeSafeDiagnosingMatcher.java:55)
at org.junit.Assert.assertThat(Assert.java:770)
at org.junit.Assert.assertThat(Assert.java:736)
at indexer.IndexerTest.testIndexContainsField(IndexerTest.java:152)

Настройка:

  • Юнит 4.11
  • Hamcrest 1.3
  • Используя плагин Maven's surefire (версия 2.14), который использует свой JUnitCoreProvider
  • Java 7 (OpenJDK)
  • Смотри Пом (commit ac72ce)

Фон:

NoSuchMethodError вызывается (скомпилированными) классами, которые вызывают несуществующие методы. Конкретный случай describeMismatch и комбинация JUnit + Hamcrest часто вызывается несовместимостью между классами Hamcrest, включенными в JUnit, и версиями этих классов в библиотеке Hamcrest.

Попытки решить ошибку NoSuchMethodError:

  • Пом содержит явную зависимость от Hamcrest-библиотеки 1.3, Hamcrest-core 1.3 и JUnit 4.11 (в таком порядке), как это было предложено Garrett Hall в ответ на получение "NoSuchMethodError: org.hamcrest.Matcher.describeMismatch" при запуске теста в IntelliJ 10,5

  • Согласно документации JUnit, зависимость JUnit 4.11 Maven больше не включает скомпилированные классы Hamcrest, вместо этого она имеет зависимость от Hamcrest-core 1.3; Итак NoSuchMethodError не должно происходить.

  • Проверка дерева зависимостей с помощью mvn dependency:tree как предложено Dan в ответе на объявление junit и hamcrest, показывает явные зависимости от Hamcrest 1.3 и JUnit 4.11 и никаких других зависимостей от этих файлов (полный вывод см. на http://db.tt/C2OfTDJB).

  • В другом тесте NoSuchMethodError удалось избежать с помощью:

    assertThat(
        "Zylab detector not available",
        d.getDetectors(),
        hasItem(Matchers.<Detector>instanceOf(ZylabMetadataXmlDetector.class)));
    

    В строках 120–123 файла IndexerTest.java (commit ac72ce) вместо более очевидного:

    assertThat(
        "Zylab detector not available",
        d.getDetectors(),
        hasItem(isA(ZylabMetadataDetector.class));
    

    Я не уверен, является ли явный параметр типа <Detector>, с помощью instanceOf вместо isA Явная ссылка на Хамкреста Matchers или сочетание тех, кто избежал NoSuchMethodException; после возни и пробуя разные вещи это сработало.

  • Использование явных параметров типа не помогло решить проблему.

  • Используя класс, полученный из BaseMatcher вместо FeatureMatcher не решить / избежать ошибки.

Идеи как починить NoSuchMethodError?

8 ответов

Решение

Этот блог помог мне решить ту же проблему:

https://tedvinke.wordpress.com/2013/12/17/mixing-junit-hamcrest-and-mockito-explaining-nosuchmethoderror/

Внутри зависимостей для Mockito и Junit автор добавил исключение:

<dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <version>4.11</version>
    <exclusions>
        <exclusion>
            <artifactId>hamcrest-core</artifactId>
            <groupId>org.hamcrest</groupId>
        </exclusion>
    </exclusions>
</dependency>

Возможно, один из тех других JAR имеет более старые версии Hamcrest's Matcher или же BaseMatcher, Вот список JAR-файлов, которые включают последний, хотя я не знаю, насколько всеобъемлющим этот сайт. Есть ли плагин Maven, который покажет вам все зависимости, которые включают класс, похожий на дерево зависимостей?

Используя подсказку David Harkness и Как мне разбить строку на разделителе в Bash? привел к следующему сценарию bash:

( IFS=":"; for i in `mvn dependency:build-classpath | grep -v '\[INFO\]'`; do jar tf $i | awk "{print \"$i\\t\" \$1}"; done | grep Matcher )

(онлайн на http://www.kaspervandenberg.net/2013/scripts/findDependencyClass.sh)

Который нашел эту зависимость JGlobus-Core-2.0.4 имеет свои версии org.hamcrest.BaseMatcher, org.hamcrest.CoreMatchers, а также org.hamcrest.Matcher,

То, что работало для меня, было изменить порядок зависимостей. Вместо того, чтобы идти mockito, junit, я должен был поставить junit, mockito.

В Mockito 1.9.5 используется Hamcrest 1.1, который несовместим и вызывает проблемы.

Если вы используете Eclipse, инструмент "Открыть тип" (CTRL+SHIFT+T) может помочь вам найти проблемный пакет. Просто найдите имя класса (например, Description), множественные вхождения одного и того же класса из разных JAR-файлов - это красные флаги.

Для проекта с Gradle в качестве инструмента сборки:

testCompile("junit:junit:4.11") {
     exclude group: 'org.hamcrest', module: 'hamcrest-core'
     exclude group: 'org.hamcrest', module: 'hamcrest-library' 
}
testCompile group: 'org.hamcrest', name: 'hamcrest-core', version: '1.3'
testCompile group: 'org.hamcrest', name: 'hamcrest-library', version: '1.3'

Если вы используете Eclipse: Для меня в eclipse-> свойства проекта->Java build Path перемещение mockito-all-1.9.5.jar в конец списка 'Order and Export' сделало свое дело. Чуть выше у меня есть junit-4.11.jar и выше этого hamcrest-core-1.3.jar

Я решил это jar hell проблема в моем Gradle проект с кодом ниже:

    testCompile (group: 'junit', name: 'junit', version: '4+') {
        exclude group: 'org.hamcrest'
    }
    testCompile ('org.mockito:mockito-core:1+') {
        exclude group: 'org.hamcrest'
    }
    testCompile 'org.hamcrest:java-hamcrest:2.0.0.0'
Другие вопросы по тегам