Obtendo “NoSuchMethodError: org.hamcrest.Matcher.describeMismatch” ao executar o teste no IntelliJ 10.5

233

Estou usando o JUnit-dep 4.10 e o Hamcrest 1.3.RC2.

Eu criei um correspondente personalizado que se parece com o seguinte:

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 perfeitamente quando executado a partir da linha de comando usando o Ant. Mas quando executado no IntelliJ, ele falha com:

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)

Meu palpite é que ele está usando o hamcrest.MatcherAssert errado. Como encontro qual hamcrest.MatcherAssert está sendo usado (ou seja, qual arquivo jar está sendo usado para hamcrest.MatcherAssert)? AFAICT, os únicos frascos de hamcrest no meu caminho de classe é 1.3.RC2.

O IntelliJ IDEA está usando sua própria cópia do JUnit ou Hamcrest?

Como eu produzo o CLASSPATH de tempo de execução que o IntelliJ está usando?

Noel Yap
fonte

Respostas:

272

Verifique se o jarro de hamcrest é mais alto no pedido de importação do que o seu jar JUnit .

O JUnit vem com sua própria org.hamcrest.Matcherclasse que provavelmente está sendo usada.

Você também pode fazer o download e usar o junit-dep-4.10.jar em vez disso, que é o JUnit sem as classes hamcrest.

O mockito também possui as classes mais vazias, então você pode precisar movê-lo / reordená-lo

Garrett Hall
fonte
1
A OP disse que eles já estavam usando o pote '-de--'. Mas você acha que está usando a classe Matcher do jar JUnit. Portanto, é provável que o IDE esteja usando sua própria cópia do JUnit.
MatrixFrog
2
Eu removi a cópia do junit.jar e do junit-4.8.jar do IntelliJ, instalei o junit-dep-4.10.jar no diretório lib / do IntelliJ e o problema ainda ocorre.
Noel Yap
8
JUnit 4.11 é compatível com Hamcrest 1.3 e JUnit 4.10 é compatível com Hamcrest 1.1 search.maven.org/remotecontent?filepath=junit/junit-dep/4.10/...
Muthu
23
Verifique se você não está usando Mockito-tudo, mas em vez Mockito-core com uma exclusão de hamcrest
Ulf Lindback
1
São 19:33 no escritório e estou trabalhando em um recurso importante que devo entregar antes de sair de férias e é sexta-feira, estou nessas férias na próxima semana !!!!!! Como diabos eu poderia obter esse erro agora !!!
Adelin 15/07
170

Esse problema também surge quando você tem mockito-all no caminho da classe, que já está obsoleto.

Se possível, inclua mockito-core .

Configuração do Maven para misturar 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>
Tom Parkinson
fonte
2
Assim como as novas versões do mockito incluem hamcrest e o powermock!
Tom Parkinson
3
Isso deveria ser mockito-core em vez de mockito-all?
user944849
3
Você pode incluir apenas o núcleo, se precisar apenas no ritmo de tudo, no entanto, o acima deve funcionar em todos os casos. A ordem das dependências é o bit importante que o mvn 3 inicia do topo em ordem de prioridade.
Tom Parkinson
3
Você não deve incluir Mockito-tudo desde que inclui hamcrest 1.1, em vez incluem Mockito-core e excluir hancrest a partir dele (que você não pode fazer de tudo)
Ulf Lindback
1
"Se possível, inclua mockito-core." OK, então por que essa resposta ainda usa mockito-all?
Rabino Stealth
60

O problema era que a classe errada hamcrest.Matcher, e não hamcrest.MatcherAssert, estava sendo usada. Isso estava sendo extraído de uma dependência junit-4.8 que uma das minhas dependências estava especificando.

Para ver quais dependências (e versões) estão incluídas em qual fonte durante o teste, execute:

mvn dependency:tree -Dscope=test
Noel Yap
fonte
5
Eu tive o mesmo problema. Eu estava usando o JUnit-dep e o Hamcrest-core, mas tinha o Powermock listado anteriormente no pom, o que resultava na inclusão do JUnit antes do JUnit-dep e do Hamcrest.
John B
9
Também mockito-all inclui algumas classes Hamcrest. É melhor usar o mockito-core e excluir a dependência oculta.
Brambo 24/04
3
Apenas tropeçou exatamente no mesmo problema. Solução foi aumentando versão junit a 4,11, que é compatível (isto é, "contém classes de") com hamcrest 1,3
r3mbol
Para aqueles em que todas as sugestões não funcionaram tão bem (ordem de dependência, exclusões, remoção de substituir -allpor -core, etc ...): tive que mudar o hamcrest de volta para a versão 1.1 e agora tudo funciona novamente.
Felix Hagspiel
1
para mim funcionou quando mudei minha importação para import static org.mockito.Matchers.anyString;de #import static org.mockito.ArgumentMatchers.anyString;
Shrikant Prabhu
28

O seguinte deve ser o mais correto hoje. Observe, a junção 4.11 depende do hamcrest-core, portanto, não é necessário especificar que o mockito-all não possa ser usado, pois inclui (não depende) 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
fonte
3
Note que o JUnit 4.12 agora depende do hamcrest-core 1.3.
JeeBee
Exclusão de mockito-allajudou para mim, não mockito-core. Também declarando Hamcrest antes de Mockito em pom.xmlobras.
21418 Kirill
13

Isso funcionou para mim depois de lutar um pouco

<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
fonte
O mesmo para mim. A colocação de dependências nessa ordem ajuda o maven a resolver deps transitivos corretamente. Excluir explicitamente o hamcrest do mockito-core ou mockito-all pode ser mais seguro, no caso de alguém reordenar os deps em seu pom.
Mat
4

Experimentar

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

ao invés de

expectMessage(message)

Você pode escrever um ExpectedExceptionmétodo personalizado ou utilitário para agrupar o código.

Qiang Li
fonte
4

Eu sei que esse é um thread antigo, mas o que resolveu o problema foi adicionar o seguinte aos meus arquivos build.gradle. Como já foi dito acima, há um problema de compatibilidade commockito-all

Mensagem possivelmente ú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
fonte
1

Apesar de ser uma pergunta muito antiga e provavelmente muitas das idéias mencionadas resolverem muitos problemas, ainda quero compartilhar a solução com a comunidade que resolveu o meu problema.

Eu descobri que o problema era uma função chamada "hasItem" que eu estava usando para verificar se um JSON-Array contém ou não um item específico. No meu caso, verifiquei um valor do tipo Long.

E isso levou ao problema.

De alguma forma, os Matchers têm problemas com valores do tipo Long. (Eu não uso tanto o JUnit ou o Rest-Assured quanto o idk. Exatamente por que, mas acho que os dados JSON retornados contêm apenas números inteiros.)

Então, o que eu fiz para resolver o problema foi o seguinte. Ao invés de usar:

long ID = ...;

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

você só precisa converter para Inteiro. Portanto, o código de trabalho ficou assim:

long ID = ...;

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

Essa provavelmente não é a melhor solução, mas eu só queria mencionar que a exceção também pode ser lançada devido a tipos de dados errados / desconhecidos.

Siro
fonte
0

O que funcionou para mim foi excluir o grupo hamcrest da compilação do teste junit.

Aqui está o código do meu build.gradle:

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

Se você estiver executando o IntelliJ, poderá ser necessário executar gradle cleanIdea idea clean buildpara detectar as dependências novamente.

Jason D
fonte
0

Sei que essa não é a melhor resposta, mas se você não conseguir fazer o caminho de classe funcionar, essa é uma solução do plano B.

No meu caminho de classe de teste, adicionei a seguinte interface com uma implementação padrão para o método descrevMismatch.

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

Eu tenho um projeto gradle e quando minha seção de dependências build.gradle se parece com isso:

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

isso leva a esta exceção:

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 corrigir esse problema, substituí "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'
}

A explicação entre mockito-all e mockito-core pode ser encontrada aqui: https://solidsoft.wordpress.com/2012/09/11/beyond-the-mockito-refcard-part-3-mockito-core-vs-mockito -todos os projetos baseados em graduação /

O mockito-all.jar além do próprio Mockito contém também (a partir do 1.9.5) duas dependências: Hamcrest e Objenesis (vamos omitir o ASM e o CGLIB reembalados por um momento). O motivo era ter tudo o que é necessário dentro de um JAR para colocá-lo em um caminho de classe. Pode parecer estranho, mas lembre-se de que o desenvolvimento do Mockito começou nos tempos em que o Ant puro (sem gerenciamento de dependências) era o sistema de construção mais popular para projetos Java e todos os JARs externos exigidos por um projeto (ou seja, as dependências do nosso projeto e suas dependências) tinham para ser baixado manualmente e especificado em um script de construção.

Por outro lado, mockito-core.jar é apenas classes Mockito (também com ASM e CGLIB reembalado). Ao usá-lo com Maven ou Gradle, as dependências necessárias (Hamcrest e Objenesis) são gerenciadas por essas ferramentas (baixadas automaticamente e colocadas em um caminho de classe de teste). Ele permite substituir as versões usadas (por exemplo, se nossos projetos usam nunca, mas a versão compatível com versões anteriores), mas o mais importante é que essas dependências não estejam ocultas no mockito-all.jar, o que permite detectar uma possível incompatibilidade de versão com as ferramentas de análise de dependência. Essa é uma solução muito melhor quando a ferramenta gerenciada por dependência é usada em um projeto.

Pavel
fonte
0

No meu caso, tive que excluir um hamcrest mais antigo do 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é
fonte
0

Isso funcionou para mim. Não há necessidade de excluir nada. Eu apenas usei mockito-corevezmockito-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
fonte