EqualityTestCase: Difference between revisions
mNo edit summary |
mNo edit summary |
||
Line 1: | Line 1: | ||
<geshi lang="java5"> | <geshi lang="java5"> | ||
import java.io.ByteArrayInputStream; | import java.io.ByteArrayInputStream; | ||
import java.io.ByteArrayOutputStream; | import java.io.ByteArrayOutputStream; | ||
Line 8: | Line 9: | ||
import java.lang.reflect.InvocationTargetException; | import java.lang.reflect.InvocationTargetException; | ||
import java.lang.reflect.Method; | import java.lang.reflect.Method; | ||
import java.util. | import java.util.ArrayList; | ||
import java.util.HashSet; | import java.util.HashSet; | ||
import java.util.Iterator; | import java.util.Iterator; | ||
Line 71: | Line 72: | ||
* | * | ||
* If the object under test implements Comparable then a < b (< c) | * If the object under test implements Comparable then a < b (< c) | ||
*/ | */ | ||
public abstract class EqualityTestCase extends TestCase { | public abstract class EqualityTestCase<T> extends TestCase { | ||
/** | /** | ||
Line 81: | Line 80: | ||
* created by getA, but be not equals to objects created by getB | * created by getA, but be not equals to objects created by getB | ||
*/ | */ | ||
protected abstract | protected abstract T getA() throws Exception; | ||
/** | /** | ||
Line 88: | Line 87: | ||
* created by getA, but be not equals to objects created by getB | * created by getA, but be not equals to objects created by getB | ||
*/ | */ | ||
protected abstract | protected abstract T getB() throws Exception; | ||
/** | /** | ||
Line 94: | Line 93: | ||
* optionally be implemented. | * optionally be implemented. | ||
*/ | */ | ||
protected | protected T getC() throws Exception { | ||
return null; | return null; | ||
} | } | ||
public void testEquals() { | public void testEquals() throws Exception { | ||
assertFalse(getA().equals(null)); | assertFalse(getA().equals(null)); | ||
assertFalse(getB().equals(null)); | assertFalse(getB().equals(null)); | ||
Line 118: | Line 117: | ||
} | } | ||
for (Iterator iterator = getObjects().iterator(); iterator.hasNext();) { | for (Iterator<T> iterator = getObjects().iterator(); iterator.hasNext();) { | ||
Object o = iterator.next(); | Object o = iterator.next(); | ||
// The equals method is reflexive, which means that an object is equal to itself: x.equals(x) should return true. | // The equals method is reflexive, which means that an object is equal to itself: x.equals(x) should return true. | ||
Line 127: | Line 126: | ||
} | } | ||
public void testHashCode() { | public void testHashCode() throws Exception { | ||
assertEquals("hashCodes differ for two A objects", getA().hashCode(), getA().hashCode()); | assertEquals("hashCodes differ for two A objects", getA().hashCode(), getA().hashCode()); | ||
assertEquals(getB().hashCode(), getB().hashCode()); | assertEquals(getB().hashCode(), getB().hashCode()); | ||
Line 142: | Line 141: | ||
} | } | ||
Set set = new HashSet(); | Set<T> set = new HashSet<T>(); | ||
set.add(getA()); | set.add(getA()); | ||
Line 150: | Line 149: | ||
} | } | ||
@SuppressWarnings("unchecked") // Comparable<T> is checked only at runtime | |||
public void testComparable() throws Exception { | public void testComparable() throws Exception { | ||
if (getA() instanceof Comparable) { | if (getA() instanceof Comparable) { | ||
assertEquals(0, ((Comparable) getA()).compareTo(getA())); | assertEquals(0, ((Comparable<T>) getA()).compareTo(getA())); | ||
assertEquals(0, ((Comparable) getB()).compareTo(getB())); | assertEquals(0, ((Comparable<T>) getB()).compareTo(getB())); | ||
assertEquals("Item B should compare equally with another item B", 0, ((Comparable<T>) getB()).compareTo(getB())); | |||
assertTrue(((Comparable) getA()).compareTo(getB()) < 0); | assertTrue("Item B should be less than Item A", ((Comparable<T>) getA()).compareTo(getB()) < 0); | ||
assertTrue(((Comparable) getB()).compareTo(getA()) > 0); | assertTrue(((Comparable<T>) getB()).compareTo(getA()) > 0); | ||
if (getC() != null) { | if (getC() != null) { | ||
assertEquals(0, ((Comparable) getC()).compareTo(getC())); | assertEquals(0, ((Comparable<T>) getC()).compareTo(getC())); | ||
assertTrue(((Comparable) getA()).compareTo(getC()) < 0); | assertTrue("Item C should be less than Item A", ((Comparable<T>) getA()).compareTo(getC()) < 0); | ||
assertTrue(((Comparable) getB()).compareTo(getC()) < 0); | assertTrue("Item C should be less than Item B", ((Comparable<T>) getB()).compareTo(getC()) < 0); | ||
assertTrue(((Comparable) getC()).compareTo(getB()) > 0); | assertTrue(((Comparable<T>) getC()).compareTo(getB()) > 0); | ||
} | } | ||
} | } | ||
Line 168: | Line 169: | ||
public void testSerializable() throws Exception { | public void testSerializable() throws Exception { | ||
if (getA() instanceof Serializable) { | if (getA() instanceof Serializable) { | ||
for ( | for (T o : getObjects()) { | ||
assertTrue(o.equals(serialize(o))); | |||
} | } | ||
} | } | ||
Line 197: | Line 197: | ||
* @throws IllegalArgumentException | * @throws IllegalArgumentException | ||
*/ | */ | ||
public void testClone() throws | public void testClone() throws Exception, | ||
IllegalAccessException, InvocationTargetException { | IllegalAccessException, InvocationTargetException { | ||
if (getA() instanceof Cloneable) { | if (getA() instanceof Cloneable) { | ||
for ( | for (T o : getObjects()) { | ||
Method clone = o.getClass().getMethod("clone", new Class[] {}); | Method clone = o.getClass().getMethod("clone", new Class[] {}); | ||
Object cloned = clone.invoke(o, new Object[] {}); | Object cloned = clone.invoke(o, new Object[] {}); | ||
Line 215: | Line 214: | ||
* this is a 'good' toString, other than to make sure the code works and doesn't return <code>null</code>. | * this is a 'good' toString, other than to make sure the code works and doesn't return <code>null</code>. | ||
*/ | */ | ||
public void testToString() { | public void testToString() throws Exception { | ||
for (Iterator iterator = getObjects().iterator(); iterator.hasNext();) { | for (Iterator<T> iterator = getObjects().iterator(); iterator.hasNext();) { | ||
Object o = iterator.next(); | Object o = iterator.next(); | ||
assertNotNull(o.toString()); | assertNotNull(o.toString()); | ||
Line 222: | Line 221: | ||
} | } | ||
/** | /** | ||
* This will either return | * This will either return a list of one or two objects depending on if getC() is implemented. | ||
* @return a list of test objects. | * @return a list of test objects. | ||
*/ | */ | ||
private | private List<T> getObjects() throws Exception { | ||
List<T> list = new ArrayList<T>(3); | |||
list.add(getA()); | |||
list.add(getB()); | |||
if (getC() != null) { | if (getC() != null) { | ||
list.add(getC()); | |||
} | } | ||
return | return list; | ||
} | } | ||
} | } |
Revision as of 03:55, 6 August 2009
<geshi lang="java5">
import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.Serializable; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Set;
import junit.framework.TestCase;
/**
* This base class is for testing that an object properly overrides * {@link Object#equals} and {@link Object#hashCode}. *
*
* Here are the important contract requirements for the two methods, as
* documented in the javadoc documentation for java.lang.Object
:
*
*
-
*
*
- The
hashCode
method must return the same integer value * every time it is invoked on the same object during the entire execution of a * Java application or applet. It need not return the same value for different * runs of an application or applet. The Java 2 platform (Java 2) documentation * further allows thehashCode
value to change if the information * used in theequals
method changes.
*
*
* - If two objects are equal according to the
equals
method, * they must return the same value fromhashCode
.
*
*
*
* - The
equals
method is reflexive, which means that an * object is equal to itself:x.equals(x)
should return true.
*
*
* - The
equals
method is symmetric: If *x.equals(y)
returns true, theny.equals(x)
* should return true also.
*
*
*
* - The
equals
method is transitive: If *x.equals(y)
returns true andy.equals(z)
* returns true, thenx.equals(z)
should return true.
*
*
* - The
equals
method is consistent.x.equals(y)
* should consistently return either true or false. The Java 2 javadoc clarifies * that the result ofx.equals(y)
can change if the information * used in the equals comparisons change.
*
*
*
* - Finally,
x.equals(null)
should return false.
*
* * Additionally, if this class implements {@link Comparable}, * {@link Serializable}, or {@link Cloneable}, then the object will be checked * to see if these methods provide reasonable behavior. * * You must implement two factory methods: getA, getB. * * If the object under test implements Comparable then a < b (< c) */
public abstract class EqualityTestCase<T> extends TestCase {
/** * * @return a new instance of an Object which should equate to other objects * created by getA, but be not equals to objects created by getB */ protected abstract T getA() throws Exception;
/** * * @return a new instance of an Object which should equate to other objects * created by getA, but be not equals to objects created by getB */ protected abstract T getB() throws Exception;
/** * @return an object which is not equal to either A or B. This method can * optionally be implemented. */ protected T getC() throws Exception { return null; }
public void testEquals() throws Exception { assertFalse(getA().equals(null)); assertFalse(getB().equals(null)); assertFalse(getA().equals(new Object())); assertFalse(getB().equals(new Object())); //The equals method is symmetric: If x.equals(y) returns true, then y.equals(x) should return true also. assertTrue(getA().equals(getA())); assertTrue(getB().equals(getB())); assertFalse(getA().equals(getB())); assertFalse(getB().equals(getA())); if (getC() != null) { assertFalse(getC().equals(null)); assertFalse(getC().equals(new Object())); assertTrue(getC().equals(getC())); assertFalse(getA().equals(getC())); assertFalse(getC().equals(getA())); assertFalse(getB().equals(getC())); assertFalse(getC().equals(getB())); }
for (Iterator<T> iterator = getObjects().iterator(); iterator.hasNext();) { Object o = iterator.next(); // The equals method is reflexive, which means that an object is equal to itself: x.equals(x) should return true. assertTrue(o.equals(o)); // x.equals(null) should return false. assertFalse(o.equals(null)); } }
public void testHashCode() throws Exception { assertEquals("hashCodes differ for two A objects", getA().hashCode(), getA().hashCode()); assertEquals(getB().hashCode(), getB().hashCode()); assertFalse("hashCode is either not implmented correctly or is very bad\n" + "Both A and B returned a hashCode of " + getA().hashCode(), getA().hashCode() == getB().hashCode()); if (getC() != null) { assertEquals(getC().hashCode(), getC().hashCode()); assertFalse("hashCode is either not implmented correctly or is very bad\n" + "Both A and C returned a hashCode of " + getA().hashCode(), getA().hashCode() == getC() .hashCode()); assertFalse("hashCode is either not implmented correctly or is very bad\n" + "Both B and C returned a hashCode of " + getB().hashCode(), getB().hashCode() == getC() .hashCode()); }
Set<T> set = new HashSet<T>(); set.add(getA());
assertTrue(set.contains(getA())); assertFalse(set.contains(getB())); assertFalse(set.contains(getC())); }
@SuppressWarnings("unchecked") // Comparable<T> is checked only at runtime public void testComparable() throws Exception { if (getA() instanceof Comparable) { assertEquals(0, ((Comparable<T>) getA()).compareTo(getA())); assertEquals(0, ((Comparable<T>) getB()).compareTo(getB())); assertEquals("Item B should compare equally with another item B", 0, ((Comparable<T>) getB()).compareTo(getB()));
assertTrue("Item B should be less than Item A", ((Comparable<T>) getA()).compareTo(getB()) < 0); assertTrue(((Comparable<T>) getB()).compareTo(getA()) > 0); if (getC() != null) { assertEquals(0, ((Comparable<T>) getC()).compareTo(getC())); assertTrue("Item C should be less than Item A", ((Comparable<T>) getA()).compareTo(getC()) < 0); assertTrue("Item C should be less than Item B", ((Comparable<T>) getB()).compareTo(getC()) < 0); assertTrue(((Comparable<T>) getC()).compareTo(getB()) > 0); } } }
public void testSerializable() throws Exception { if (getA() instanceof Serializable) { for (T o : getObjects()) { assertTrue(o.equals(serialize(o))); } } }
private Object serialize(Object value) throws IOException, ClassNotFoundException { ByteArrayOutputStream outputBuffer = new ByteArrayOutputStream(); ObjectOutputStream outputStream = new ObjectOutputStream(outputBuffer); outputStream.writeObject(value); outputStream.flush(); byte[] bytes = outputBuffer.toByteArray(); ByteArrayInputStream inputStream = new ByteArrayInputStream(bytes); ObjectInputStream objectInputStream = new ObjectInputStream(inputStream); return objectInputStream.readObject(); }
/** * If you must implement {@link java.lang.Cloneable}, please do it correctly! The clone interface doesn't require * you to make 'clone' a public method, but this what one generally expects for an object which * implements {@link java.lang.Cloneable} * * @throws NoSuchMethodException * @throws SecurityException * @throws InvocationTargetException * @throws IllegalAccessException * @throws IllegalArgumentException */ public void testClone() throws Exception, IllegalAccessException, InvocationTargetException { if (getA() instanceof Cloneable) { for (T o : getObjects()) { Method clone = o.getClass().getMethod("clone", new Class[] {}); Object cloned = clone.invoke(o, new Object[] {}); assertNotSame(o, cloned); assertEquals(o, cloned); assertEquals(o.getClass(), cloned.getClass()); } } }
/**
* toString doesn't have to be implemented. There's not a lot of checks we can do to make sure
* this is a 'good' toString, other than to make sure the code works and doesn't return null
.
*/
public void testToString() throws Exception {
for (Iterator<T> iterator = getObjects().iterator(); iterator.hasNext();) {
Object o = iterator.next();
assertNotNull(o.toString());
}
}
/**
* This will either return a list of one or two objects depending on if getC() is implemented.
* @return a list of test objects.
*/
private List<T> getObjects() throws Exception {
List<T> list = new ArrayList<T>(3);
list.add(getA());
list.add(getB());
if (getC() != null) {
list.add(getC());
}
return list;
}
}
</geshi>