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?

xander27
fonte

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.

Joe
fonte
+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.

Jofsey
fonte
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 ...)

rvazquezglez
fonte
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).

yvolk
fonte
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.

Jim Jarrett
fonte
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.

Borjab
fonte
-3

Para comparar duas listas com a ordem de uso preservado,

assertThat(actualList, contains("item1","item2"));
Shravan Ramamurthy
fonte
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