Obtention de «NoSuchMethodError: org.hamcrest.Matcher.describeMismatch» lors de l'exécution du test dans IntelliJ 10.5

233

J'utilise JUnit-dep 4.10 et Hamcrest 1.3.RC2.

J'ai créé un matcher personnalisé qui ressemble à ceci:

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 */
    }
}

Il fonctionne parfaitement bien lorsqu'il est exécuté à partir de la ligne de commande en utilisant Ant. Mais lorsqu'il est exécuté à partir d'IntelliJ, il échoue avec:

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)

Je suppose qu'il utilise le mauvais hamcrest.MatcherAssert. Comment puis-je trouver quel hamcrest.MatcherAssert il utilise (c'est-à-dire quel fichier jar il utilise pour hamcrest.MatcherAssert)? AFAICT, le seul bocal Hamcrest de mon chemin de classe est le 1.3.RC2.

IntelliJ IDEA utilise-t-il sa propre copie de JUnit ou Hamcrest?

Comment puis-je générer le CLASSPATH d'exécution utilisé par IntelliJ?

Noel Yap
la source

Réponses:

272

Assurez-vous que le pot hamcrest est plus élevé dans l'ordre d'importation que votre pot JUnit .

JUnit est livré avec sa propre org.hamcrest.Matcherclasse qui est probablement utilisée à la place.

Vous pouvez également télécharger et utiliser à la place le junit-dep-4.10.jar qui est JUnit sans les classes hamcrest.

mockito contient également les classes hamcrest, vous devrez donc peut-être le déplacer \ réorganiser également

Garrett Hall
la source
1
OP a déclaré qu'ils utilisaient déjà le pot «-dep-». Mais votre supposition qu'il utilise la classe Matcher du pot JUnit sonne bien. C'est donc probablement que l'EDI utilise sa propre copie de JUnit.
MatrixFrog
2
J'ai supprimé la copie d'IntelliJ de junit.jar et junit-4.8.jar, installé junit-dep-4.10.jar dans le répertoire lib / d'IntelliJ, et le problème persiste.
Noel Yap
8
JUnit 4.11 est compatible avec Hamcrest 1.3 et JUnit 4.10 est compatible avec Hamcrest 1.1 search.maven.org/remotecontent?filepath=junit/junit-dep/4.10/…
Muthu
23
assurez-vous que vous n'utilisez PAS mockito-all, mais plutôt mockito-core avec une exclusion de hamcrest
Ulf Lindback
1
Il est 19h33 au bureau et je travaille sur une fonctionnalité importante que je dois livrer avant de partir en vacances et c'est vendredi, je suis en vacances la semaine prochaine !!!!!! Comment diable j'ai pu obtenir cette erreur maintenant !!!
Adelin
170

Ce problème se produit également lorsque vous avez mockito-all sur votre chemin de classe, qui est déjà obsolète.

Si possible, incluez simplement mockito-core .

Config Maven pour mélanger junit, mockito et 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>
Tom Parkinson
la source
2
Tout comme les nouvelles versions de mockito incluent hamcrest également avec powermock!
Tom Parkinson
3
Cela devrait-il être mockito-core au lieu de mockito-all?
user944849
3
Vous pouvez inclure uniquement le noyau si vous n'en avez besoin que dans le rythme de tous, mais ce qui précède devrait fonctionner dans tous les cas. L'ordre des dépendances est le bit important mvn 3 part du haut par ordre de priorité.
Tom Parkinson
3
Vous ne devez PAS inclure mockito-all car cela inclut hamcrest 1.1, au lieu d'inclure mockito-core et en exclure hancrest (ce que vous ne pouvez pas faire de tous)
Ulf Lindback
1
"Si possible, il suffit d'inclure mockito-core.". OK, alors pourquoi cette réponse utilise-t-elle toujours mockito-all?
Rabbin furtif
60

Le problème était que la mauvaise classe hamcrest.Matcher, non hamcrest.MatcherAssert, était utilisée. Cela était tiré d'une dépendance junit-4.8 que l'une de mes dépendances spécifiait.

Pour voir quelles dépendances (et versions) sont incluses à partir de quelle source pendant le test, exécutez:

mvn dependency:tree -Dscope=test
Noel Yap
la source
5
J'ai eu le même problème. J'utilisais JUnit-dep et Hamcrest-core mais j'avais Powermock répertorié plus tôt dans le pom, ce qui entraînait l'inclusion de JUnit avant JUnit-dep et Hamcrest.
John B
9
Mockito-all comprend également des cours Hamcrest. Il est préférable d'utiliser mockito-core et d'exclure la dépendance hamcrest.
Brambo
3
Je suis juste tombé sur le même problème. La solution augmentait la version junit à 4.11 qui est compatible (c'est-à-dire "contient des classes de") avec hamcrest 1.3
r3mbol
Pour ceux où toutes les suggestions ne fonctionnaient pas aussi bien (ordre de dépendance, exclusions, suppression du remplacement -allpar -core, etc ...): J'ai dû changer hamcrest en version 1.1 et maintenant tout fonctionne à nouveau.
Felix Hagspiel
1
pour moi, cela a fonctionné lorsque j'ai changé mon importation import static org.mockito.Matchers.anyString;deimport static org.mockito.ArgumentMatchers.anyString;
Shrikant Prabhu
28

Ce qui suit devrait être le plus correct aujourd'hui. Remarque, junit 4.11 dépend de hamcrest-core, vous ne devriez donc pas avoir besoin de spécifier que mockito-all ne peut pas être utilisé car il inclut (ne dépend pas de) 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>
Ulf Lindback
la source
3
Notez que JUnit 4.12 dépend maintenant de hamcrest-core 1.3.
JeeBee
Exclusion de mockito-all m'a aidé, non mockito-core. Déclarant également Hamcrest devant Mockito en pom.xmltravaux.
Kirill
13

Cela a fonctionné pour moi après un peu de difficulté

<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
la source
Pareil pour moi. Mettre les dépendances dans cet ordre aide maven à résoudre correctement les dépôts transitifs. Exclure explicitement le hamcrest du mockito-core ou du mockito-all pourrait être plus sûr, au cas où quelqu'un réorganiserait des deps dans votre pom.
Mat
4

Essayer

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

au lieu de

expectMessage(message)

Vous pouvez écrire une ExpectedExceptionméthode personnalisée ou utilitaire pour terminer le code.

Qiang Li
la source
4

Je sais que c'est un vieux fil, mais ce qui a résolu le problème pour moi, c'est l'ajout de ce qui suit à mes fichiers build.gradle. Comme déjà indiqué ci-dessus, il existe un problème de compatibilité avecmockito-all

Poste éventuellement utile :

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'
Kai
la source
1

Malgré le fait qu'il s'agit d'une question très ancienne et que bon nombre des idées susmentionnées ont résolu de nombreux problèmes, je souhaite toujours partager la solution avec la communauté qui a résolu mon problème.

J'ai trouvé que le problème était une fonction appelée "hasItem" que j'utilisais pour vérifier si un tableau JSON contient ou non un élément spécifique. Dans mon cas, j'ai vérifié une valeur de type Long.

Et cela a conduit au problème.

D'une manière ou d'une autre, les Matchers ont des problèmes avec les valeurs de type Long. (Je n'utilise pas JUnit ou Rest-Assured tellement idk. Exactement pourquoi, mais je suppose que les données JSON renvoyées ne contiennent que des entiers.)

Donc, ce que j'ai fait pour résoudre le problème était le suivant. À la place d'utiliser:

long ID = ...;

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

il vous suffit de lancer sur Integer. Le code de travail ressemblait donc à ceci:

long ID = ...;

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

Ce n'est probablement pas la meilleure solution, mais je voulais juste mentionner que l'exception peut également être levée en raison de types de données incorrects / inconnus.

Siro
la source
0

Ce qui a fonctionné pour moi, c'était d'exclure le groupe hamcrest de la compilation des tests junit.

Voici le code de mon build.gradle:

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

Si vous exécutez IntelliJ, vous devrez peut-être exécuter gradle cleanIdea idea clean buildpour détecter à nouveau les dépendances.

Jason D
la source
0

Je sais que ce n'est pas la meilleure réponse, mais si vous ne pouvez pas faire fonctionner le chemin de classe, c'est une solution de plan B.

Dans mon chemin de classe de test, j'ai ajouté l'interface suivante avec une implémentation par défaut pour la méthode describeMismatch.

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_();
}
Francis
la source
0

J'ai un projet gradle et lorsque ma section de dépendances build.gradle ressemble à ceci:

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

cela conduit à cette exception:

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)

pour résoudre ce problème, j'ai remplacé "mockito-all" par "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'
}

L'explication entre mockito-all et mockito-core peut être trouvée ici: https://solidsoft.wordpress.com/2012/09/11/beyond-the-mockito-refcard-part-3-mockito-core-vs-mockito -tous les projets basés sur Mavengradle /

mockito-all.jar en plus de Mockito lui-même contient également (à partir de 1.9.5) deux dépendances: Hamcrest et Objenesis (omettons ASM et CGLIB reconditionnés pendant un moment). La raison était d'avoir tout ce dont on avait besoin dans un seul JAR pour le mettre sur un chemin de classe. Cela peut sembler étrange, mais n'oubliez pas que le développement de Mockito a commencé à une époque où Pure Ant (sans gestion des dépendances) était le système de construction le plus populaire pour les projets Java et tous les JAR externes requis par un projet (c'est-à-dire les dépendances de notre projet et leurs dépendances). à télécharger manuellement et à spécifier dans un script de construction.

D'un autre côté, mockito-core.jar n'est que des classes Mockito (également avec ASM et CGLIB reconditionnés). Lorsque vous l'utilisez avec Maven ou Gradle, les dépendances requises (Hamcrest et Objenesis) sont gérées par ces outils (téléchargées automatiquement et placées sur un chemin de classe de test). Il permet de remplacer les versions utilisées (par exemple si nos projets utilisent jamais, mais une version rétrocompatible), mais ce qui est plus important, ces dépendances ne sont pas cachées dans mockito-all.jar ce qui permet de détecter une éventuelle incompatibilité de version avec les outils d'analyse de dépendance. C'est une bien meilleure solution lorsque l'outil de gestion des dépendances est utilisé dans un projet.

Pavel
la source
0

Dans mon cas, j'ai dû exclure un hamcrest plus ancien de 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>
André
la source
0

Cela a fonctionné pour moi. Pas besoin d'exclure quoi que ce soit. Je l'ai juste utilisé à la mockito-coreplacemockito-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'
Joni Lappalainen
la source