2010-12-15 52 views

Respuesta

56

Cada vez que anulo el código equino y el código hash, escribo pruebas unitarias que siguen las recomendaciones de Joshua Bloch en "Java efectivo" Capítulo 3. Me aseguro de que los códigos equivoctivo y reflexivo sean reflexivos, simétricos y transitivos. También me aseguro de que "no igual" funcione correctamente para todos los miembros de datos.

Cuando verifico la llamada a igual, también me aseguro de que hashCode se comporte como debería. De esta manera:

@Test 
public void testEquals_Symmetric() { 
    Person x = new Person("Foo Bar"); // equals and hashCode check name field value 
    Person y = new Person("Foo Bar"); 
    Assert.assertTrue(x.equals(y) && y.equals(x)); 
    Assert.assertTrue(x.hashCode() == y.hashCode()); 
} 
+9

Además de esto, podría agregar que sería razonable probar que las modificaciones a campos que no son clave no provoquen que se genere un código hash modificado. Además, las modificaciones a los campos clave causan hashCodes modificados. –

+0

Creo que no deberíamos probar otro método, ya que esta prueba solo es para código hash, solo deben compararse los códigos hash y el resto del código debe tomarse en igual prueba y debe probarse por separado –

+0

Seis años después y todavía estoy en desacuerdo con usted. No hay diferencia que yo pueda ver. Necesitan ser anulados juntos; ellos pueden ser probados juntos. Si necesita pruebas por separado, olvídese. – duffymo

1

No creo que haya una necesidad de probar un método de código hash. Especialmente si es generado por su IDE o HashCodeBuilder (apache commons)

+1

Leer el código, es posiblemente la mejor verificación para garantizar que tenga sentido. es decir, es difícil encontrar casos patológicos por ensayo y error. –

4

Cree muchos (millones de) objetos aleatorios reproducibles y agregue todos los hashCodes a un conjunto y verifique que obtenga casi y muchos valores únicos como el número de generar identificadores Para hacerlos reproducibles al azar, usa una semilla aleatoria fija.

Además, compruebe que puede agregar estos elementos a un HashSet y encontrarlos nuevamente. (Utilizando un objeto diferente con los mismos valores)

Asegúrate de que tu igual() coincide con tu comportamiento hashCode(). También verificaría que tus campos sean todos finales.

+17

He votado negativamente por la simple razón de que agregar aleatoriedad a una prueba unitaria es una cosa mala, ya que lo primero que quieres saber es * por qué * la prueba falló, lo cual es muy difícil si sus entradas son aleatorias. Además, es posible que necesite ejecutar miles de millones de objetos a través de su método de código hash para obtener confianza, y eso puede significar que su prueba de unidad tarda mucho tiempo en ejecutarse, lo cual también es algo malo. – PaulJWilliams

+1

No se dan razones para los votos a la baja. Una explicación sería útil. –

+2

@Visage, cómo el uso de datos no aleatorios le indica por qué falla una prueba, todo lo que necesita es reproducibilidad para ayudar a diagnosticar una prueba fallida. No puede alcanzar el nivel de prueba que reclama con un desarrollo impulsado por pruebas realista. Sin embargo, puede decir que cuando la prueba falla, tiene un problema. –

3

hashCode está anulado para hacer instancias con los mismos campos idénticos para HashSet/HashMap etc. Así que la prueba Junit debe afirmar que dos instancias diferentes con los mismos valores devuelven idéntico hashCode.

+0

Muchas gracias. –

+1

Una prueba es útil, pero probar millones de valores sería más útil y aún tardaría menos de un segundo. –

5

Cuando se escribe una función matemática en general (como el código hash) de probar algunos ejemplos en sus pruebas hasta que esté convencido de que la función funciona como se esperaba. Cuántos ejemplos dependen de tu función.

Para una función de código hash, creo que probará al menos que dos objetos distintos, que se consideran iguales, tienen el mismo código hash. Al igual que

assertNotSame(obj1, obj2); // don't cheat 
assertEquals(obj1.hashcode(), obj2.hashcode()); 

Después sería conveniente probar que dos valores diferentes tienen diferentes códigos hash para evitar la aplicación de hashcode() como return 1;.

0

Además de @duffymo prueba para hashcode ser reflexivo, simétrico y transitivo, otra forma de prueba sería a través de "Mapa" que es donde los códigos de hash realmente son útiles.

@Test 
public void testHashcode() { 
    Person p1 = new Person("Foo Bar"); 
    Person p2 = new Person("Foo Bar"); 
    Map<Person, String> map = new HashMap<>(); 
    map.put(p1, "dummy"); 
    Assert.assertEquals("dummy", map.get(p2)); 
} 
Cuestiones relacionadas