Uzyskiwanie „NoSuchMethodError: org.hamcrest.Matcher.describeMismatch” podczas uruchamiania testu w IntelliJ 10.5

233

Używam JUnit-dep 4.10 i Hamcrest 1.3.RC2.

Utworzyłem niestandardowy moduł dopasowywania, który wygląda następująco:

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

Działa idealnie dobrze, gdy jest uruchamiany z wiersza poleceń za pomocą Ant. Ale uruchamiany z IntelliJ nie działa z:

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)

Domyślam się, że używa niewłaściwego hamcrest.MatcherAssert. Jak mogę znaleźć, którego hamcrest.MatcherAssert używa (tzn. Jakiego pliku jar używa dla hamcrest.MatcherAssert)? AFAICT, jedyne słoiki hamcrest w mojej ścieżce klas to 1.3.RC2.

Czy IntelliJ IDEA korzysta z własnej kopii JUnit lub Hamcrest?

Jak wyprowadzić środowisko wykonawcze CLASSPATH, którego używa IntelliJ?

Noel Yap
źródło

Odpowiedzi:

272

Upewnij się, że słoik hamcrest jest wyżej w kolejności importu niż słoik JUnit .

JUnit ma własną org.hamcrest.Matcherklasę, która prawdopodobnie jest używana w zamian.

Możesz także pobrać plik junit-dep-4.10.jar i użyć go zamiast JUnit bez klas hamcrest.

mockito ma również w sobie klasy hamcrest, więc może być konieczne przeniesienie go i zmiana kolejności

Garrett Hall
źródło
1
OP powiedział, że już używają słoika „-dep-”. Ale twoje przypuszczenie, że używa klasy Matcher ze słoika JUnit, brzmi dobrze. Prawdopodobnie więc IDE używa własnej kopii JUnit.
MatrixFrog
2
Usunąłem kopię IntelliJ z junit.jar i junit-4.8.jar, zainstalowałem junit-dep-4.10.jar w katalogu lib / IntelliJ i problem nadal występuje.
Noel Yap
8
JUnit 4.11 jest kompatybilny z Hamcrest 1.3, a JUnit 4.10 jest kompatybilny z Hamcrest 1.1 search.maven.org/remotecontent?filepath=junit/junit-dep/4.10/…
Muthu
23
upewnij się, że NIE używasz mockito-all, ale zamiast tego mockito-core z wyłączeniem hamcrestu
Ulf Lindback
1
W biurze jest 19:33 i pracuję nad ważną funkcją, którą muszę dostarczyć przed wyjazdem na wakacje. Jest piątek, jestem na wakacjach w przyszłym tygodniu !!!!!! Jak do cholery mogłem dostać ten błąd teraz !!!
Adelin
170

Ten problem pojawia się także, gdy na ścieżce klasy znajduje się mockito-all , który jest już przestarzały.

Jeśli to możliwe, po prostu dołącz rdzeń-mockito .

Konfiguracja Maven do miksowania junit, mockito i 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
źródło
2
Zupełnie nowe wersje mockito obejmują również hamcrest z powermockiem!
Tom Parkinson
3
Czy powinno to być mockito-core zamiast mockito-all?
user944849
3
Możesz dołączyć tylko rdzeń, jeśli potrzebujesz go tylko we wszystkim, jednak powyższe powinno działać we wszystkich przypadkach. Kolejność zależności jest ważnym bitem mvn 3, który zaczyna się od góry w kolejności pierwszeństwa.
Tom Parkinson
3
NIE powinieneś włączać mockito-all, ponieważ obejmuje to hamcrest 1.1, zamiast tego włącz rdzeń mockito i wyklucz z niego hancrest (czego nie możesz zrobić od wszystkich)
Ulf Lindback
1
„Jeśli to możliwe, po prostu dołącz mockito-core.”. OK, więc dlaczego ta odpowiedź nadal używa mockito-all?
Stealth Rabbi
60

Problem polegał na tym , że użyto niewłaściwej hamcrest.Matcher, a nie hamcrest.MatcherAssertklasy. To było wyciągane z zależności junit-4.8, którą określiła jedna z moich zależności.

Aby zobaczyć, jakie zależności (i wersje) są zawarte z jakiego źródła podczas testowania, uruchom:

mvn dependency:tree -Dscope=test
Noel Yap
źródło
5
Miałem ten sam problem. Używałem JUnit-dep i Hamcrest-core, ale miałem Powermock wymieniony wcześniej w pom, co spowodowało włączenie JUnit przed JUnit-dep i Hamcrest.
John B
9
Również mockito-all obejmuje niektóre klasy Hamcrest. Lepiej jest użyć rdzenia mockito i wykluczyć zależność od hamcrestu.
Brambo
3
Natknąłem się na dokładnie ten sam problem. Roztwór upping junit do wersji 4.11, który jest zgodny (czyli „zawiera zajęcia z”) z hamcrest 1.3
r3mbol
Dla tych, gdzie wszystkie propozycje nie działa tak dobrze (Dependency kolejności exlusions, usuwając zastąpić -allz -core, etc ...): Musiałem zmienić hamcrest powrotem do wersji 1.1 i teraz wszystko działa ponownie.
Felix Hagspiel
1
dla mnie zadziałało, kiedy zmieniłem import import static org.mockito.Matchers.anyString;zimport static org.mockito.ArgumentMatchers.anyString;
Shrikant Prabhu
28

Poniższe informacje powinny być dziś najbardziej poprawne. Uwaga, junit 4.11 zależy od rdzenia hamcrest, więc nie musisz wcale określać, że mockito-all nie może być używane, ponieważ obejmuje (nie zależy) 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
źródło
3
Zauważ, że JUnit 4.12 zależy teraz od rdzenia hamcrest 1.3.
JeeBee,
Wyłączenie z mockito-allpomocy mi pomogło, nie mockito-core. Deklarowanie Hamcrest przed Mockito w pom.xmldziełach.
Kirill
13

To działało dla mnie po trochę zmaganiu się

<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
źródło
Dla mnie to samo. Umieszczenie zależności w tej kolejności pomaga maven poprawnie rozwiązać przechodnie. Wyraźne wyłączenie hamcrestu z mockito-core lub mockito-all może być jednak bezpieczniejsze, na wypadek, gdyby ktoś zmienił kolejność w twojej pom.
Mat
4

Próbować

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

zamiast

expectMessage(message)

Możesz napisać niestandardową ExpectedExceptionlub użyteczną metodę, aby zakończyć kod.

Qiang Li
źródło
4

Wiem, że to stary wątek, ale rozwiązaniem mojego problemu było dodanie następujących plików do moich plików build.gradle. Jak już wspomniano powyżej, występuje problem ze zgodnościąmockito-all

Prawdopodobnie przydatny post :

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
źródło
1

Pomimo tego, że jest to bardzo stare pytanie i prawdopodobnie wiele z wyżej wymienionych pomysłów rozwiązało wiele problemów, nadal chcę podzielić się rozwiązaniem ze społecznością, która naprawiła mój problem.

Odkryłem, że problemem była funkcja o nazwie „hasItem”, której używałem do sprawdzenia, czy tablica JSON zawiera określony element. W moim przypadku sprawdziłem wartość typu Long.

To doprowadziło do problemu.

W jakiś sposób Matchery mają problemy z wartościami typu Long. (Nie używam JUnit ani Rest-Assured tak bardzo idk. Dokładnie dlaczego, ale wydaje mi się, że zwrócone dane JSON zawierają tylko liczby całkowite.)

Więc to, co zrobiłem, aby rozwiązać problem, było następujące. Zamiast używać:

long ID = ...;

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

po prostu musisz rzucić na Integer. Tak działający kod wyglądał następująco:

long ID = ...;

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

Prawdopodobnie nie jest to najlepsze rozwiązanie, ale chciałem tylko wspomnieć, że wyjątek może zostać zgłoszony również z powodu niewłaściwych / nieznanych typów danych.

Siro
źródło
0

To, co zadziałało, to wykluczenie grupy hamcrest z kompilacji testu junit.

Oto kod z mojego build.gradle:

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

Jeśli korzystasz z IntelliJ, może być konieczne uruchomienie w gradle cleanIdea idea clean buildcelu ponownego wykrycia zależności.

Jason D.
źródło
0

Wiem, że nie jest to najlepsza odpowiedź, ale jeśli nie możesz uruchomić ścieżki klas, jest to rozwiązanie typu B.

W mojej testowej ścieżce klas dodałem następujący interfejs z domyślną implementacją dla metody replaceMismatch.

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
źródło
0

Mam projekt gradle i kiedy moja sekcja zależności build.gradle wygląda następująco:

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

prowadzi to do tego wyjątku:

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)

Aby rozwiązać ten problem, podstawiłem „mockito-all” na „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'
}

Wyjaśnienie między mockito-all i mockito-core można znaleźć tutaj: https://solidsoft.wordpress.com/2012/09/11/beyond-the-mockito-refcard-part-3-mockito-core-vs-mockito -wszystkie projekty oparte na mengengradle /

mockito-all.jar oprócz samego Mockito zawiera także (od wersji 1.9.5) dwie zależności: Hamcrest i Objenesis (pomińmy na chwilę przepakowane ASM i CGLIB). Powodem było posiadanie wszystkiego, co jest potrzebne w jednym pliku JAR, aby po prostu umieścić go w ścieżce klas. Może to wyglądać dziwnie, ale pamiętaj, że rozwój Mockito rozpoczął się w czasach, gdy czysta Mrówka (bez zarządzania zależnościami) była najpopularniejszym systemem kompilacji dla projektów Java i wszystkie zewnętrzne pliki JAR wymagane przez projekt (tj. Zależności naszego projektu i ich zależności) miały do pobrania ręcznie i określone w skrypcie kompilacji.

Z drugiej strony mockito-core.jar to tylko klasy Mockito (również z ponownie zapakowanym ASM i CGLIB). Podczas korzystania z Maven lub Gradle wymagane zależności (Hamcrest i Objenesis) są zarządzane przez te narzędzia (pobierane automatycznie i uruchamiane testową ścieżką klas). Pozwala to na zastąpienie używanych wersji (na przykład, jeśli nasze projekty używają nigdy wersji kompatybilnej z poprzednimi wersjami), ale co ważniejsze, te zależności nie są ukryte w mockito-all.jar, co pozwala wykryć możliwą niezgodność wersji z narzędziami analizy zależności. Jest to znacznie lepsze rozwiązanie, gdy w projekcie używane jest narzędzie do zarządzania zależnościami.

Pavel
źródło
0

W moim przypadku musiałem wykluczyć starszy hamcrest z 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é
źródło
0

To zadziałało dla mnie. Nie musisz niczego wykluczać. Właśnie użyłem mockito-corezamiast tegomockito-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
źródło