Obteniendo "NoSuchMethodError: org.hamcrest.Matcher.describeMismatch" al ejecutar la prueba en IntelliJ 10.5

233

Estoy usando JUnit-dep 4.10 y Hamcrest 1.3.RC2.

He creado un matizador personalizado que se parece a lo siguiente:

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

Funciona perfectamente bien cuando se ejecuta desde la línea de comando usando Ant. Pero cuando se ejecuta desde IntelliJ, falla 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)

Mi conjetura es que está usando el hamcrest incorrecto. MatcherAssert. ¿Cómo encuentro qué hamcrest.MatcherAssert está usando (es decir, qué archivo jar está usando para hamcrest.MatcherAssert)? AFAICT, los únicos tarros de Hamcrest en mi classpath son 1.3.RC2.

¿IntelliJ IDEA usa su propia copia de JUnit o Hamcrest?

¿Cómo envío el CLASSPATH en tiempo de ejecución que IntelliJ está usando?

Noel Yap
fuente

Respuestas:

272

Asegúrese de que el tarro de Hamcrest sea ​​más alto en el pedido de importación que su tarro JUnit .

JUnit viene con su propia org.hamcrest.Matcherclase que probablemente se esté utilizando en su lugar.

También puede descargar y usar junit-dep-4.10.jar, que es JUnit sin las clases de Hamcrest.

mockito también tiene las clases de hamcrest, así que es posible que también necesites moverlo / reordenarlo

Garrett Hall
fuente
1
OP dijo que ya estaban usando el tarro '-dep-'. Pero su suposición de que está usando la clase Matcher del JUnit jar suena bien. Entonces es probable que el IDE esté usando su propia copia de JUnit.
MatrixFrog
2
Eliminé la copia de IntelliJ de junit.jar y junit-4.8.jar, instalé junit-dep-4.10.jar en el directorio lib / de IntelliJ, y el problema aún ocurre.
Noel Yap
8
JUnit 4.11 es compatible con Hamcrest 1.3 y JUnit 4.10 es compatible con Hamcrest 1.1 search.maven.org/remotecontent?filepath=junit/junit-dep/4.10/…
Muthu
23
asegúrese de NO usar mockito-all, sino mockito-core con la exclusión de hamcrest
Ulf Lindback
1
Son las 7:33 PM en la oficina y estoy trabajando en una característica importante que debo entregar antes de salir de vacaciones y ¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡!!!! ¡Cómo demonios podría obtener este error ahora!
Adelin
170

Este problema también surge cuando tienes mockito-all en tu ruta de clase, que ya está en desuso.

Si es posible, solo incluya mockito-core .

Configuración de Maven para mezclar junit, mockito y 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
fuente
2
¡Como las nuevas versiones de mockito incluyen hacrest también lo mismo con powermock!
Tom Parkinson
3
¿Debería ser mockito-core en lugar de mockito-all?
user944849
3
Puede incluir solo core si solo lo necesita al ritmo de todos, sin embargo, lo anterior debería funcionar en todos los casos. El orden de las dependencias es el bit importante mvn 3 comienza desde arriba en orden de prioridad.
Tom Parkinson
3
NO debes incluir mockito-all ya que eso incluye hamcrest 1.1, en su lugar incluye mockito-core y excluir hancrest de él (que no puedes hacer de todos)
Ulf Lindback
1
"Si es posible, solo incluya mockito-core". Bien, entonces ¿por qué esta respuesta todavía usa mockito-all?
Stealth Rabino
60

El problema era que se estaba usando la clase incorrecta hamcrest.Matcher, no hamcrest.MatcherAssert. Eso estaba siendo extraído de una dependencia junit-4.8 que una de mis dependencias estaba especificando.

Para ver qué dependencias (y versiones) se incluyen de qué fuente durante la prueba, ejecute:

mvn dependency:tree -Dscope=test
Noel Yap
fuente
55
Tuve el mismo problema. Estaba usando JUnit-dep y Hamcrest-core pero tenía Powermock enumerado anteriormente en el pom, lo que resultó en que JUnit se incluyera antes de JUnit-dep y Hamcrest.
John B
99
También mockito-all incluye algunas clases de Hamcrest. Es mejor usar mockito-core y excluir la dependencia de Hamcrest.
Brambo
3
Acabo de encontrar exactamente el mismo problema. La solución fue aumentar la versión junit a 4.11, que es compatible (es decir, "contiene clases de") con Hamcrest 1.3
r3mbol
Para aquellos en los que todas las sugerencias no funcionaron tan bien (orden de dependencia, extracciones, eliminación de reemplazo -allcon -core, etc.): tuve que cambiar Hamcrest a la versión 1.1 y ahora todo funciona de nuevo.
Felix Hagspiel
1
para mí funcionó cuando cambié mi importación import static org.mockito.Matchers.anyString;deimport static org.mockito.ArgumentMatchers.anyString;
Shrikant Prabhu
28

Lo siguiente debería ser lo más correcto hoy. Tenga en cuenta que junit 4.11 depende de hamcrest-core, por lo que no debería necesitar especificar que no se puede usar mockito-all ya que incluye (no depende 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
fuente
3
Tenga en cuenta que JUnit 4.12 ahora depende de hamcrest-core 1.3.
JeeBee
La exclusión de mockito-allme ayudó, no mockito-core. También declarando Hamcrest ante Mockito en pom.xmlobras.
Kirill
13

Esto funcionó para mí después de luchar un poco

<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
fuente
Lo mismo para mi. Poner las dependencias en este orden ayuda a Maven a resolver los depósitos transitivos correctamente. Sin embargo, excluir explícitamente Hamcrest de mockito-core o mockito-all podría ser más seguro, en caso de que alguien reordene los departamentos en su pom.
Mat
4

Tratar

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

en vez de

expectMessage(message)

Puede escribir un ExpectedExceptionmétodo personalizado o de utilidad para envolver el código.

Qiang Li
fuente
4

Sé que este es un hilo antiguo, pero lo que resolvió el problema para mí fue agregar lo siguiente a mis archivos build.gradle. Como ya se indicó anteriormente, hay un problema de compatibilidad conmockito-all

Posible publicación útil :

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

A pesar del hecho de que esta es una pregunta muy antigua y probablemente muchas de las ideas antes mencionadas resolvieron muchos problemas, todavía quiero compartir la solución con la comunidad que solucionó mi problema.

Descubrí que el problema era una función llamada "hasItem" que estaba usando para verificar si un JSON-Array contiene o no un elemento específico. En mi caso, verifiqué un valor de tipo Long.

Y esto condujo al problema.

De alguna manera, los Matchers tienen problemas con los valores de tipo Long. (No uso JUnit o Rest-Assured tanto, idk. Exactamente por qué, pero supongo que los datos JSON devueltos solo contienen números enteros).

Entonces, lo que hice para solucionar el problema fue lo siguiente. En lugar de usar:

long ID = ...;

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

solo tienes que lanzar a Integer. Entonces el código de trabajo se veía así:

long ID = ...;

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

Probablemente esa no sea la mejor solución, pero solo quería mencionar que la excepción también se puede lanzar debido a tipos de datos incorrectos / desconocidos.

Siro
fuente
0

Lo que funcionó para mí fue excluir al grupo de Hamcrest de la compilación de prueba junit.

Aquí está el código de mi build.gradle:

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

Si está ejecutando IntelliJ, es posible que deba ejecutar gradle cleanIdea idea clean buildpara detectar las dependencias nuevamente.

Jason D
fuente
0

Sé que esa no es la mejor respuesta, pero si no puede hacer que el classpath funcione, esta es una solución del plan B.

En mi classpath de prueba, agregué la siguiente interfaz con una implementación predeterminada para el método 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
fuente
0

Tengo un proyecto gradle y cuando mi sección de dependencias build.gradle se ve así:

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

conduce a esta excepción:

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)

Para solucionar este problema, he sustituido "mockito-all" por "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 explicación entre mockito-all y mockito-core se puede encontrar aquí: https://solidsoft.wordpress.com/2012/09/11/beyond-the-mockito-refcard-part-3-mockito-core-vs-mockito -todos-en-mavengradle-based-projects /

mockito-all.jar además de Mockito en sí contiene también (a partir de 1.9.5) dos dependencias: Hamcrest y Objenesis (omita por un momento ASM y CGLIB reempaquetados). La razón era tener todo lo que se necesita dentro de un JAR para ponerlo en un classpath. Puede parecer extraño, pero recuerde que el desarrollo de Mockito comenzó en momentos en que Ant puro (sin administración de dependencias) era el sistema de compilación más popular para proyectos Java y todos los JAR externos requeridos por un proyecto (es decir, las dependencias de nuestro proyecto y sus dependencias) tenían para descargarse manualmente y especificarse en un script de compilación.

Por otro lado, mockito-core.jar es solo clases de Mockito (también con ASM y CGLIB reempaquetados). Cuando se usa con Maven o Gradle, las dependencias requeridas (Hamcrest y Objenesis) son administradas por esas herramientas (descargadas automáticamente y puestas en un classpath de prueba). Permite anular versiones usadas (por ejemplo, si nuestros proyectos usan una versión nunca compatible, pero compatible con versiones anteriores), pero lo que es más importante esas dependencias no están ocultas dentro de mockito-all.jar, lo que permite detectar posibles incompatibilidades de versiones con herramientas de análisis de dependencia. Esta es una solución mucho mejor cuando la herramienta administrada por dependencia se utiliza en un proyecto.

Pavel
fuente
0

En mi caso, tuve que excluir una hamaca más antigua 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é
fuente
0

Esto funcionó para mí. No es necesario excluir nada. Acabo de utilizar mockito-coreen su lugarmockito-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
fuente