Digamos que eu tenha uma classe sem o método equals (), para a qual não tenho a fonte. Eu quero afirmar a igualdade em duas instâncias dessa classe.
Posso fazer várias afirmações:
assertEquals(obj1.getFieldA(), obj2.getFieldA());
assertEquals(obj1.getFieldB(), obj2.getFieldB());
assertEquals(obj1.getFieldC(), obj2.getFieldC());
...
Não gosto dessa solução porque não consigo entender o quadro completo da igualdade se uma declaração inicial falhar.
Posso comparar manualmente por conta própria e acompanhar o resultado:
String errorStr = "";
if(!obj1.getFieldA().equals(obj2.getFieldA())) {
errorStr += "expected: " + obj1.getFieldA() + ", actual: " + obj2.getFieldA() + "\n";
}
if(!obj1.getFieldB().equals(obj2.getFieldB())) {
errorStr += "expected: " + obj1.getFieldB() + ", actual: " + obj2.getFieldB() + "\n";
}
...
assertEquals("", errorStr);
Isso me dá uma imagem completa da igualdade, mas é desajeitado (e eu nem mesmo considerei os possíveis problemas nulos). Uma terceira opção é usar Comparator, mas compareTo () não me dirá quais campos falharam na igualdade.
Existe uma prática melhor para obter o que desejo do objeto, sem subclassificar e substituir equals (ugh)?
java
unit-testing
junit
Ryan Nelson
fonte
fonte
equal
método apenas informa se duas instâncias são iguais e não nos importamos por que as intâncias não são iguais.Object
s têm umequals
método, você provavelmente não quis dizer nenhum método igual a substituído.Respostas:
Mockito oferece um combinador de reflexão:
Para a versão mais recente do Mockito, use:
Para versões mais antigas, use:
fonte
org.mockito.internal.matchers.apachecommons
. Mockito docs declara:org.mockito.internal
-> "Classes internas, não devem ser usadas por clientes." Você vai colocar seu projeto em risco usando isso. Isso pode mudar em qualquer versão do Mockito. Leia aqui: site.mockito.org/mockito/docs/current/overview-summary.htmlMockito.refEq()
lugar.Mockito.refEq()
falha quando os objetos não têm um id definido = (refEq
falha para comparar, pois o método hashcode não é capaz de comparar os objetos.Existem muitas respostas corretas aqui, mas eu gostaria de adicionar minha versão também. Isso é baseado em Assertj.
ATUALIZAÇÃO: No assertj v3.13.2, este método está obsoleto, conforme apontado por Woodz em comentário. A recomendação atual é
fonte
usingRecursiveComparison()
comisEqualTo()
, de modo que a linha éassertThat(actualObject).usingRecursiveComparison().isEqualTo(expectedObject);
Eu geralmente implemento este caso de uso usando org.apache.commons.lang3.builder.EqualsBuilder
fonte
Eu sei que é um pouco velho, mas espero que ajude.
Encontro o mesmo problema que você, então, após investigação, encontrei poucas perguntas semelhantes a esta, e, depois de encontrar a solução, estou respondendo o mesmo nessas, pois achei que poderia ajudar outras pessoas.
A resposta mais votada (não aquela escolhida pelo autor) para esta pergunta semelhante , é a solução mais adequada para você.
Basicamente, consiste em usar a biblioteca chamada Unitils .
Este é o uso:
O que passará mesmo que a classe
User
não implementeequals()
. Você pode ver mais exemplos e uma declaração muito legal chamadaassertLenientEquals
em seu tutorial .fonte
Unitils
parece que morreu, consulte stackoverflow.com/questions/34658067/is-unitils-project-alive .Você pode usar Apache commons lang ReflectionToStringBuilder
Você pode especificar os atributos que deseja testar um por um ou, melhor, excluir aqueles que não deseja:
Você então compara as duas strings normalmente. Para o ponto sobre a reflexão ser lenta, presumo que seja apenas para teste, então não deve ser tão importante.
fonte
Se você estiver usando o hamcrest para suas declarações (assertThat) e não quiser puxar libs de teste adicionais, você pode usar
SamePropertyValuesAs.samePropertyValuesAs
para declarar itens que não têm um método igual a sobrescrito.A vantagem é que você não precisa puxar mais um framework de teste e ele apresentará um erro útil quando o assert falhar (
expected: field=<value> but was field=<something else>
) em vez deexpected: true but was false
se você usar algo comoEqualsBuilder.reflectionEquals()
.A desvantagem é que é uma comparação superficial e não há opção para excluir campos (como no EqualsBuilder), então você terá que contornar objetos aninhados (por exemplo, removê-los e compará-los independentemente).
Melhor caso:
Caso feio:
Então, escolha seu veneno. Estrutura adicional (por exemplo, Unitils), erro inútil (por exemplo, EqualsBuilder) ou comparação superficial (hamcrest).
fonte
A biblioteca Hamcrest 1.3 Utility Matchers tem um matcher especial que usa reflexão em vez de igual.
fonte
Alguns dos métodos de comparação de reflexão são superficiais
Outra opção é converter o objeto em um json e comparar as strings.
fonte
Usando o Shazamcrest , você pode fazer:
fonte
reflectEquals
retornafalse
quando os objetos possuem referências diferentes.Compare campo por campo:
fonte
As asserções AssertJ podem ser usadas para comparar os valores sem o
#equals
método devidamente substituído, por exemplo:fonte
Como essa pergunta é antiga, vou sugerir outra abordagem moderna usando JUnit 5.
Com o JUnit 5, há um método chamado
Assertions.assertAll()
que permitirá agrupar todas as asserções em seu teste e executará cada uma e produzirá quaisquer asserções com falha no final. Isso significa que qualquer asserção que falhe primeiro não interromperá a execução das afirmações posteriores.fonte
Você pode usar a reflexão para "automatizar" o teste de igualdade completo. você pode implementar o código de "rastreamento" de igualdade que escreveu para um único campo e, em seguida, usar reflexão para executar esse teste em todos os campos do objeto.
fonte
Este é um método de comparação genérico, que compara dois objetos de uma mesma classe por seus valores de seus campos (tenha em mente que eles são acessíveis pelo método get)
fonte
Me deparei com um caso muito semelhante.
Eu queria comparar em um teste que um objeto tinha os mesmos valores de atributos como outro, mas métodos, como
is()
,refEq()
, etc não iria funcionar por razões como meu objeto com um valor nulo em seuid
atributo.Então esta foi a solução que encontrei (bem, um colega de trabalho encontrou):
Se o valor obtido de
reflectionCompare
for 0, significa que são iguais. Se for -1 ou 1, eles diferem em alguns atributos.fonte
Em um caso comum com AssertJ, você pode criar uma estratégia de comparação personalizada:
Usando uma estratégia de comparação personalizada em asserções
Exemplos AssertJ
fonte
Eu tive exatamente o mesmo enigma ao testar a unidade de um aplicativo Android, e a solução mais fácil que encontrei foi simplesmente usar o Gson para converter meus objetos de valor real e esperado
json
e compará-los como strings.As vantagens disso sobre a comparação manual de campo por campo é que você compara todos os seus campos, portanto, mesmo se mais tarde adicionar um novo campo à sua classe, ele será testado automaticamente, em comparação a se você estivesse usando um monte de
assertEquals()
on todos os campos, que precisariam ser atualizados se você adicionar mais campos à sua classe.jUnit também exibe as strings para que você possa ver diretamente onde elas diferem. Não tenho certeza de quão confiável é o ordenamento de campo
Gson
, porém, isso pode ser um problema potencial.fonte
Tentei todas as respostas e nada realmente funcionou para mim.
Então, criei meu próprio método que compara objetos java simples sem ir fundo em estruturas aninhadas ...
O método retorna nulo se todos os campos corresponderem ou string contendo detalhes de incompatibilidade.
Apenas as propriedades que possuem um método getter são comparadas.
Como usar
Saída de amostra se houver uma incompatibilidade
A saída mostra os nomes das propriedades e respectivos valores dos objetos comparados
Código (Java 8 e superior):
fonte
Como alternativa para junit apenas, você pode definir os campos como nulos antes da asserção igual a:
fonte
Você pode colocar o código de comparação postado em algum método de utilitário estático?
Então, você pode usar este método no JUnit assim:
assertEquals ("Objetos não são iguais", "", findDifferences (obj1, obj));
que não é desajeitado e fornece informações completas sobre as diferenças, se elas existirem (embora não seja exatamente na forma normal de assertEqual, mas você obtém todas as informações, então deve ser bom).
fonte
Isso não vai ajudar o OP, mas pode ajudar qualquer desenvolvedor C # que acabe aqui ...
Como Enrique postou , você deve substituir o método equals.
Minha sugestão é não usar uma subclasse. Use uma aula parcial.
Definições de classe parcial (MSDN)
Então, sua aula ficaria como ...
Para Java, eu concordaria com a sugestão de usar reflexão. Lembre-se de que você deve evitar o uso de reflexos sempre que possível. É lento, difícil de depurar e ainda mais difícil de manter no futuro porque os IDEs podem quebrar seu código fazendo uma renomeação de campo ou algo parecido. Seja cuidadoso!
fonte
De seus comentários a outras respostas, não entendo o que você quer.
Apenas para fins de discussão, digamos que a classe substituiu o método equals.
Portanto, seu UT será parecido com:
E você está pronto. Além disso, você não pode obter a "imagem de igualdade total" se a afirmação falhar.
Pelo que entendi, você está dizendo que mesmo se o tipo substituísse igual, você não estaria interessado nele, pois deseja obter a "imagem de igualdade total". Portanto, também não há nenhum ponto em estender e substituir iguais.
Portanto, você tem opções: comparar propriedade por propriedade, usando reflexão ou verificações embutidas em código, eu sugeriria o último. Ou: compare representações legíveis por humanos desses objetos.
Por exemplo, você pode criar uma classe auxiliar que serializa o tipo que deseja comparar a um documento XML e, em seguida, compare o XML resultante! neste caso, você pode ver visualmente o que exatamente é igual e o que não é.
Essa abordagem lhe dará a oportunidade de ver a imagem completa, mas também é relativamente complicada (e um pouco sujeita a erros no início).
fonte
Você pode substituir o método equals da classe como:
Bem, se você quiser comparar dois objetos de uma classe, você deve implementar de alguma forma o equals e o método de código hash
fonte