Hamcrest compara coleções


114

Estou tentando comparar 2 listas:

assertThat(actual.getList(), is(Matchers.containsInAnyOrder(expectedList)));

Mas ideia

java: no suitable method found for assertThat(java.util.List<Agent>,org.hamcrest.Matcher<java.lang.Iterable<? extends model.Agents>>)
method org.junit.Assert.<T>assertThat(T,org.hamcrest.Matcher<T>) is not applicable
  (no instance(s) of type variable(s) T exist so that argument type org.hamcrest.Matcher<java.lang.Iterable<? extends model.Agents>> conforms to formal parameter type org.hamcrest.Matcher<T>)
method org.junit.Assert.<T>assertThat(java.lang.String,T,org.hamcrest.Matcher<T>) is not applicable
  (cannot instantiate from arguments because actual and formal argument lists differ in length)

Como devo escrever?

Respostas:


161

Se você quiser afirmar que as duas listas são idênticas, não complique as coisas com Hamcrest:

assertEquals(expectedList, actual.getList());

Se você realmente pretende realizar uma comparação sem containsInAnyOrderdiferenciação de pedido, pode chamar o método varargs e fornecer valores diretamente:

assertThat(actual.getList(), containsInAnyOrder("item1", "item2"));

(Supondo que sua lista seja de String, em vez de Agent, para este exemplo.)

Se você realmente deseja chamar esse mesmo método com o conteúdo de um List:

assertThat(actual.getList(), containsInAnyOrder(expectedList.toArray(new String[expectedList.size()]));

Sem isso, você está chamando o método com um único argumento e criando um Matcherque espera corresponder a um Iterableonde cada elemento é um List. Isso não pode ser usado para corresponder a List.

Ou seja, você não pode combinar a List<Agent>com a Matcher<Iterable<List<Agent>>, que é o que seu código está tentando.


+1 para o "Se você realmente deseja chamar esse mesmo método com o conteúdo de uma lista". Infelizmente, eu não consegui resolver isso sozinho. Especialmente que existe um construtor que leva em uma coleção.
— Eyad Ebrahim

3
@Tim Não exatamente; containsInAnyOrderrequer que todos os elementos estejam presentes, para que a primeira afirmação falhe. Veja hasItemsse você deseja verificar se pelo menos esses elementos estão presentes.
— Joe

4
Se você usar containsInAnyOrder, deve primeiro certificar-se de que ambas as listas têm o mesmo tamanho ... Se actual.getList()acontecer de conter "item1", "item3", "item2", o teste será aprovado e talvez você queira ter certeza de que contém apenas os itens listados ... Nesse caso, você pode usar assertThat(actual.getList().size(), equalTo(2));antes de containsInAnyOrder, dessa forma você garante que ambas as listas tenham o mesmo conteúdo.
— Martin de

1
@Martin você está pensando hasItems. A verificação extra é desnecessária aqui. Veja o comentário de Tim acima e também Como os hasItems, contains e containsInAnyOrder de Hamcrest diferem?
— Joe

1
Usuários do Kotlin : não se esqueça de adicionar o operador spread ( *expectedList.toTypedArray()) ao passar um array como varargs!
— James Bowman

62
List<Long> actual = Arrays.asList(1L, 2L);
List<Long> expected = Arrays.asList(2L, 1L);
assertThat(actual, containsInAnyOrder(expected.toArray()));

Versão mais curta da resposta de @Joe sem parâmetros redundantes.


28

Para complementar a resposta de @Joe:

O Hamcrest fornece três métodos principais para combinar uma lista:

contains Verifica a correspondência de todos os elementos levando em conta a ordem, se a lista tiver mais ou menos elementos, ela falhará

containsInAnyOrder Verifica se há correspondência de todos os elementos e não importa a ordem, se a lista tiver mais ou menos elementos, irá falhar

hasItems Verifica apenas os objetos especificados, não importa se a lista tem mais

hasItem Verifica apenas um objeto, não importa se a lista tem mais

Todos eles podem receber uma lista de objetos e usar equalsmétodo para comparação ou podem ser misturados com outros matchers como o @borjab mencionado:

assertThat(myList , contains(allOf(hasProperty("id", is(7L)), 
                                   hasProperty("name", is("testName1")),
                                   hasProperty("description", is("testDesc1"))),
                             allOf(hasProperty("id", is(11L)), 
                                   hasProperty("name", is("testName2")),
                                   hasProperty("description", is("testDesc2")))));

http://hamcrest.org/JavaHamcrest/javadoc/1.3/org/hamcrest/Matchers.html#contains (E ...) http://hamcrest.org/JavaHamcrest/javadoc/1.3/org/hamcrest/Matchers.html #containsInAnyOrder (java.util.Collection) http://hamcrest.org/JavaHamcrest/javadoc/1.3/org/hamcrest/Matchers.html#hasItems (T ...)


Um pouco tarde para a festa, mas obrigado pela descrição das diferenças entre cada método.
— Marcos de Andrade

Ótima decisão caso os itens da lista não sejam do tipo primitivo.
— Stanislav Tsepa

Existe uma maneira segura de fazer isso?
— andresp

15

Com as bibliotecas Hamcrest existentes (a partir da v.2.0.0.0), você é forçado a usar o método Collection.toArray () em sua coleção para usar o Matcher containsInAnyOrder. Muito melhor seria adicionar isso como um método separado para org.hamcrest.Matchers:

public static <T> org.hamcrest.Matcher<java.lang.Iterable<? extends T>> containsInAnyOrder(Collection<T> items) {
    return org.hamcrest.collection.IsIterableContainingInAnyOrder.<T>containsInAnyOrder((T[]) items.toArray());
}

Na verdade, acabei adicionando esse método à minha biblioteca de teste customizada e usei-o para aumentar a legibilidade dos meus casos de teste (devido à menor verbosidade).


2
Boa, vou usar este ajudante. A mensagem de declaração aqui é mais informativa: ela nomeia os itens ausentes um por um, não apenas: a lista deve ser elem1, elem2, .. elem99, mas eu tenho elem1, elem2, ..., elem98 - boa sorte encontrando o que faltava.
— pihentagy

3

Certifique-se de que os Objects em sua lista os equals()definiram. Então

    assertThat(generatedList,is(equalTo(expectedList)));

trabalho.


1

Para uma lista de objetos, você pode precisar de algo assim:

import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.contains;
import static org.hamcrest.Matchers.allOf;
import static org.hamcrest.beans.HasPropertyWithValue.hasProperty;
import static org.hamcrest.Matchers.is;

@Test
@SuppressWarnings("unchecked")
public void test_returnsList(){

    arrange();
  
    List<MyBean> myList = act();
    
    assertThat(myList , contains(allOf(hasProperty("id",          is(7L)), 
                                       hasProperty("name",        is("testName1")),
                                       hasProperty("description", is("testDesc1"))),
                                 allOf(hasProperty("id",          is(11L)), 
                                       hasProperty("name",        is("testName2")),
                                       hasProperty("description", is("testDesc2")))));
}

Use containsInAnyOrder se não quiser verificar a ordem dos objetos.

PS Qualquer ajuda para evitar o aviso que é suprimido será muito apreciada.


-3

Para comparar duas listas com a ordem de uso preservado,

assertThat(actualList, contains("item1","item2"));

Isso não responde à pergunta.
— Kamczak

É parcialmente.
— rvazquezglez

@rvazquezglez O que você quer dizer? Por que você diz isso? O resultado do método está certo no meu ambiente.
— niaomingjian

@niaomingjian O código está verificando se actualListcontém os elementos dentro do containsmatcher, que falhará se os elementos não estiverem na mesma ordem e falhará também se contiver mais elementos ou estiver faltando um.
— rvazquezglez

@rvazquezglez então o propósito do código é examinar a igualdade exata (mesmos comprimentos, valores e ordem) em duas listas, certo?
— niaomingjian
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.