Ottenere "NoSuchMethodError: org.hamcrest.Matcher.describeMismatch" durante l'esecuzione del test in IntelliJ 10.5


233

Sto usando JUnit-dep 4.10 e Hamcrest 1.3.RC2.

Ho creato un abbinamento personalizzato simile al seguente:

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

Funziona perfettamente quando eseguito dalla riga di comando utilizzando Ant. Ma quando eseguito da IntelliJ, non riesce con:

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)

La mia ipotesi è che stia usando hamcrest.MatcherAssert sbagliato. Come trovo quale hamcrest.MatcherAssert sta usando (cioè quale file jar sta usando per hamcrest.MatcherAssert)? AFAICT, l'unico vasetto più amaro del mio percorso di classe è 1.3.RC2.

IntelliJ IDEA utilizza la propria copia di JUnit o Hamcrest?

Come posso generare CLASSPATH di runtime che IntelliJ sta usando?

Risposte:


272

Assicurati che il vaso hamcrest sia più alto nell'ordine di importazione rispetto al tuo vaso JUnit .

JUnit viene fornito con una propria org.hamcrest.Matcherclasse che probabilmente viene utilizzata al suo posto.

Puoi anche scaricare e usare junit-dep-4.10.jar invece che è JUnit senza le classi hamcrest.

mockito ha anche le classi più amatoriali, quindi potrebbe essere necessario spostarlo \ riordinarlo pure


1
OP ha detto che stavano già usando il vaso '-dep-'. Ma la tua ipotesi che sta usando la classe Matcher dal vaso JUnit suona bene. Quindi è probabilmente che l'IDE sta usando la propria copia di JUnit.
MatrixFrog,

2
Ho rimosso la copia di junit.jar e junit-4.8.jar di IntelliJ, installato junit-dep-4.10.jar nella directory lib / di IntelliJ e il problema persiste.
Noel Yap,

8
JUnit 4.11 è compatibile con Hamcrest 1.3 e JUnit 4.10 è compatibile con Hamcrest 1.1 search.maven.org/remotecontent?filepath=junit/junit-dep/4.10/…
Muthu

23
assicurati di NON utilizzare mockito-all, ma invece mockito-core con l'esclusione di hamcrest
Ulf Lindback

1
Sono le 19:33 in ufficio e sto lavorando a una funzione importante che devo fornire prima di uscire in vacanza ed è venerdì, sono in quella vacanza la prossima settimana !!!!!! Come diavolo ho potuto ottenere questo errore ora !!!
Adelin,

170

Questo problema si pone anche quando hai mockito-tutto sul tuo percorso di classe, che è già deprecato.

Se possibile, includi semplicemente mockito-core .

Config Maven per la miscelazione di junit, mockito e 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
Abbastanza come le nuove versioni di mockito includono hamcrest anche lo stesso con powermock!
Tom Parkinson,

3
Dovrebbe essere mockito-core anziché mockito-all?
user944849

3
Potresti includere solo core se ne hai bisogno solo al ritmo di tutti, tuttavia quanto sopra dovrebbe funzionare in tutti i casi. L'ordine delle dipendenze è il bit importante che mvn 3 parte dall'alto in ordine di priorità.
Tom Parkinson,

3
NON dovresti includere mockito-all dal momento che include hamcrest 1.1, invece includi mockito-core ed escludi hancrest da esso (cosa che non puoi fare da tutti)
Ulf Lindback

1
"Se possibile includi semplicemente mockito-core.". OK, allora perché questa risposta usa ancora mockito-all?
Rabbino

60

Il problema era che veniva usata la classe sbagliata hamcrest.Matcher, no hamcrest.MatcherAssert. Ciò veniva attirato da una dipendenza junit-4.8 specificata da una delle mie dipendenze.

Per vedere quali dipendenze (e versioni) sono incluse da quale sorgente durante il test, eseguire:

mvn dependency:tree -Dscope=test

5
Ho avuto lo stesso problema. Stavo usando JUnit-dep e Hamcrest-core ma avevo Powermock elencato in precedenza nel pom, il che stava portando l'inclusione di JUnit prima di JUnit-dep e Hamcrest.
Giovanni B,

9
Anche mockito-all include alcune classi Hamcrest. È meglio usare mockito-core ed escludere la dipendenza più grave.
Brambo,

3
Mi sono appena imbattuto nello stesso identico problema. La soluzione stava aumentando la versione junit alla 4.11 che è compatibile (cioè "contiene classi da") con hamcrest 1.3
r3mbol

Per quelli in cui tutti i suggerimenti non hanno funzionato bene (ordine di dipendenza, esclusioni, rimozione di sostituzione -allcon -core, ecc ...): ho dovuto cambiare hamcrest alla versione 1.1 e ora tutto funziona di nuovo.
Felix Hagspiel, l'

1
per me ha funzionato quando ho cambiato la mia importazione in import static org.mockito.Matchers.anyString;daimport static org.mockito.ArgumentMatchers.anyString;
Shrikant Prabhu il

28

Quanto segue dovrebbe essere il più corretto oggi. Nota, junit 4.11 dipende da hamcrest-core, quindi non dovresti specificare che mockito-all non può essere usato poiché include (non dipende da) 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
Nota che JUnit 4.12 ora dipende da hamcrest-core 1.3.
JeeBee,

L'esclusione da mockito-allme aiutata, non mockito-core. Dichiarando anche Hamcrest prima di Mockito nelle pom.xmlopere.
Kirill

13

Questo ha funzionato per me dopo aver lottato un po '

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

Stessa cosa per me. Mettere le dipendenze in questo ordine aiuta Maven a risolvere correttamente i deps transitivi. Escludere esplicitamente hamcrest da mockito-core o mockito-tutto potrebbe essere più sicuro, nel caso in cui qualcuno riordini i dettagli nel tuo pom.
Mat,

4

Provare

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

invece di

expectMessage(message)

È possibile scrivere un ExpectedExceptionmetodo personalizzato o di utilità per racchiudere il codice.


4

So che questo è un vecchio thread, ma ciò che ha risolto il problema per me è stato l'aggiunta di quanto segue ai miei file build.gradle. Come già detto sopra, esiste un problema di compatibilità conmockito-all

Post forse 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'

1

Nonostante si tratti di una domanda molto antica e probabilmente molte delle idee sopra menzionate hanno risolto molti problemi, voglio comunque condividere la soluzione con la comunità che ha risolto il mio problema.

Ho scoperto che il problema era una funzione chiamata "hasItem" che stavo usando per verificare se un array JSON contiene o meno un elemento specifico. Nel mio caso ho verificato il valore di tipo Long.

E questo ha portato al problema.

In qualche modo, i Matcher hanno problemi con i valori di tipo Long. (Non uso JUnit o Rest-Assured così tanto idk. Esattamente perché, ma immagino che i dati JSON restituiti contengano solo numeri interi.)

Quindi quello che ho fatto per risolvere il problema è stato il seguente. Invece di usare:

long ID = ...;

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

devi solo lanciare Integer. Quindi il codice di lavoro sembrava così:

long ID = ...;

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

Questa non è probabilmente la soluzione migliore, ma volevo solo menzionare che l'eccezione può essere generata anche a causa di tipi di dati errati / sconosciuti.


0

Ciò che ha funzionato per me è stato l'esclusione del gruppo hamcrest dalla compilazione del test junit.

Ecco il codice dal mio build.gradle:

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

Se si esegue IntelliJ potrebbe essere necessario eseguire gradle cleanIdea idea clean build per rilevare nuovamente le dipendenze.


0

So che non è la risposta migliore, ma se non riesci a far funzionare il percorso di classe, questa è una soluzione di piano B.

Nel mio percorso di prova, ho aggiunto la seguente interfaccia con un'implementazione predefinita per il metodo descrittoMismatch.

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

Ho un progetto gradle e quando la mia sezione delle dipendenze build.gradle appare così:

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

porta a questa eccezione:

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)

per risolvere questo problema, ho sostituito "mockito-all" con "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'
}

La spiegazione tra mockito-all e mockito-core è disponibile qui: https://solidsoft.wordpress.com/2012/09/11/beyond-the-mockito-refcard-part-3-mockito-core-vs-mockito progetti -all-in-mavengradle-Based-/

mockito-all.jar oltre a Mockito stesso contiene anche (a partire dalla 1.9.5) due dipendenze: Hamcrest e Objenesis (omettiamo per un momento di riconfezionare ASM e CGLIB). Il motivo era di avere tutto ciò che è necessario all'interno di un unico JAR per inserirlo in un percorso di classe. Può sembrare strano, ma ricorda che lo sviluppo di Mockito è iniziato in tempi in cui la formica pura (senza gestione delle dipendenze) era il sistema di build più popolare per i progetti Java e tutti i JAR esterni richiesti da un progetto (ovvero le dipendenze del nostro progetto e le loro dipendenze) avevano per essere scaricato manualmente e specificato in uno script di build.

D'altra parte mockito-core.jar sono solo classi Mockito (anche con ASM e CGLIB riconfezionati). Quando lo si utilizza con Maven o Gradle le dipendenze richieste (Hamcrest e Objenesis) sono gestite da quegli strumenti (scaricati automaticamente e inseriti in un percorso di classe di test). Permette di sovrascrivere le versioni usate (ad esempio se i nostri progetti utilizzano mai, ma versioni compatibili con le versioni precedenti), ma ciò che è più importante quelle dipendenze non sono nascoste all'interno di mockito-all.jar ciò che consente di rilevare possibili incompatibilità di versione con strumenti di analisi delle dipendenze. Questa è una soluzione molto migliore quando viene utilizzato lo strumento di gestione delle dipendenze in un progetto.


0

Nel mio caso, ho dovuto escludere un hamcrest più vecchio da 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

Questo ha funzionato per me. Non è necessario escludere nulla. Ho appena usato mockito-coreinvecemockito-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'
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.