Comment doit-on unité de tester le hashCode égal contrat?
En un mot, le hashCode contrat, en fonction de Java de l'objet.hashCode():
- Le code de hachage ne devrait pas changer à moins que quelque chose de touchant equals() changements
- equals() implique des codes de hachage sont ==
Supposons intérêt principalement dans les données immuables objets - leur de l'information ne change jamais une fois qu'ils sont construits, par conséquent, #1 est supposé tenir. Que les feuilles n ° 2: le problème est simplement celui de la confirmation, qui est égal implique code de hachage ==.
Évidemment, on ne peut pas tester tous les moyens imaginables pour objet de données, à moins que l'ensemble est infiniment faible. Alors, quelle est la meilleure façon d'écrire un test unitaire qui est susceptible d'attraper le cas?
Depuis les instances de cette classe sont immuables, il y a peu de façons de construire un tel objet; ce test devrait couvrir tous d'entre eux si possible. Sur le dessus de ma tête, les points d'entrée sont les constructeurs, la désérialisation, et les constructeurs de sous-classes (qui devrait être réductible à l'appel du constructeur de problème).
[Je vais essayer de répondre à ma propre question, à travers la recherche. L'entrée d'autres StackOverflowers est un bienvenue mécanisme de sécurité pour ce processus.]
[Ce qui pourrait être applicable à d'autres langages à objets, donc je vais ajouter cette balise.]
Vous devez vous connecter pour publier un commentaire.
EqualsVerifier est un relativement nouveau projet open source et il fait un très bon travail à l'essai de l'est égal à contrat. Il n'a pas la questions la EqualsTester de GSBase a. Je vous le conseille.
Mon conseil serait de penser à pourquoi/comment cela pourrait jamais pas vrai, et puis écrire des tests unitaires qui cible les situations.
Par exemple, disons que vous avez une coutume
Set
classe. Deux ensembles sont égaux s'ils contiennent les mêmes éléments, mais il est possible que les données sous-jacentes des structures de deux ensembles égaux à varier si ces éléments sont stockés dans un ordre différent. Par exemple:Dans ce cas, l'ordre des éléments dans les ensembles peuvent affecter leurs hachage, en fonction de l'algorithme de hachage vous avez mis en œuvre. C'est le genre de test que je ferais, car il teste le cas où je sais qu'il serait possible pour certains algorithme de hachage pour produire des résultats différents pour les deux objets que j'ai défini pour être égaux.
Vous devez utiliser une norme similaire avec votre propre classe, quelle qu'elle soit.
Il vaut la peine de l'utilisation de junit addons pour cela. Découvrez la classe EqualsHashCodeTestCase http://junit-addons.sourceforge.net/ vous pouvez l'étendre et de mettre en œuvre la méthode createInstance et createNotEqualInstance, il s'agira de vérifier la equals et hashCode méthodes sont correctes.
Je recommanderais le EqualsTester de GSBase. Il fait ce que vous voulez. J'ai deux (petits) problèmes avec elle si:
[Au moment d'écrire ces lignes, les trois autres réponses ont été publiées.]
Pour rappel, le but de ma question est de trouver le cas standard de tests pour confirmer que
hashCode
etequals
sont d'accord avec les uns des autres. Mon approche de cette question est d'imaginer le commun des chemins pris par les programmeurs lors de l'écriture de classes en question, à savoir, des données immuables. Par exemple:equals()
sans écrirehashCode()
. Cela veut souvent dire que l'égalité a été défini pour signifier l'égalité des champs des deux instances.hashCode()
sans écrireequals()
. Cela peut signifier que le programmeur a la recherche d'une plus efficace algorithme de hachage.Dans le cas du n ° 2, le problème semble inexistant pour moi. Aucune des instances supplémentaires ont été apportées
equals()
, de sorte qu'aucune des instances supplémentaires sont requis pour l'égalité des codes de hachage. Au pire, l'algorithme de hachage peut donner une moins bonne performance pour le hachage des cartes, ce qui est en dehors de la portée de cette question.Dans le cas de #1, le standard de l'unité de test implique la création de deux instances d'un même objet avec les mêmes données passées au constructeur, et la vérification de l'égalité des codes de hachage. Que sur les faux positifs? Il est possible de choisir les paramètres du constructeur qui vient de se produire à rendement égal des codes de hachage sur un néanmoins hasardeux de l'algorithme. Un test unitaire qui tend à éviter que de tels paramètres à respecter l'esprit de cette question. Le raccourci ici est d'inspecter le code source pour
equals()
, réfléchir et d'écrire un essai sur cette base, mais c'est peut-être nécessaire, dans certains cas, il peut également y avoir des tests courants que les prises, les problèmes les plus courants et ces tests permettent aussi de respecter l'esprit de cette question.Par exemple, si la classe à tester (appel de Données) est un constructeur qui prend une Chaîne de caractères, et les instances construit à partir de Chaînes de caractères qui sont
equals()
a abouti à des instances qui ont étéequals()
, puis un bon test serait probablement test:new Data("foo")
new Data("foo")
On peut même vérifier le code de hachage pour
new Data(new String("foo"))
, à force de la Chaîne de ne pas être internés, même si c'est plus à même de donner un bon code de hachage deData.equals()
est pour donner un résultat correct, à mon avis.Eli Courtwright la réponse est un exemple de vraiment réfléchir à un moyen de casser l'algorithme de hachage basée sur la connaissance de la
equals
spécification. L'exemple d'une collection est une bonne idée, que l'utilisateur faitCollection
s faire tourner à la fois, et sont tout à fait enclins à muckups dans l'algorithme de hachage.C'est l'un des seuls cas où j'aurais de multiples affirme dans un test. Puisque vous avez besoin de tester la méthode equals vous devriez également vérifier la méthode hashCode en même temps. Donc sur chacun de vos méthode equals des cas de test à vérifier le hashCode contrat en tant que bien.
Et bien sûr la vérification pour une bonne hashCode est un autre exercice. Honnêtement, je n'aurais pas pris la peine de faire le double vérifier que le hashCode n'était pas en train de changer dans la même exécution, ce genre de problème est mieux géré par l'attraper dans une revue de code et d'aider le développeur à comprendre pourquoi ce n'est pas une bonne façon d'écrire des méthodes hashCode.
Vous pouvez également utiliser quelque chose de similaire à http://code.google.com/p/guava-libraries/source/browse/guava-testlib/src/com/google/common/testing/EqualsTester.java
pour tester equals et hashCode.
Si j'ai une classe
Thing
, comme la plupart des autres dois-je écrire une classeThingTest
, qui détient tous les tests unitaires pour la classe. ChaqueThingTest
a une méthodeet si le
Thing
classe substitue hashCode et equals il a une méthodeCette méthode est responsable de la vérification de tous invariants qui sont conçus pour tenir entre n'importe quelle paire de
Thing
objets. LeObjectTest
méthode il délégués est responsable de la vérification de tous les invariants qui doit contenir entre toute paire d'objets. Commeequals
ethashCode
sont des méthodes de tous les objets, cette méthode vérifie quehashCode
etequals
sont cohérentes.J'ai ensuite quelques méthodes de test que créer des paires de
Thing
objets, et de les transmettre à l'pairescheckInvariants
méthode. J'utilise l'équivalence de partitionnement de décider ce que les paires sont intéressants. J'ai l'habitude de créer chaque paire d'être différent dans un seul attribut, en plus d'un test qui teste l'équivalent de deux objets.J'ai aussi parfois un argument 3
checkInvariants
méthode, bien que je trouve qu'il est moins utile dans findinf défauts, donc je ne fais pas cela souvent