一直听说junit的源码非常漂亮,里面用到了很多设计模式,也一直没有时间读,最近闲来无事,从今天开始阅读。
我也不知道怎么有效的阅读源码,也没先去看看junit的架构,所以就将源码导入到eclipse中,从头开始一个一个类慢慢看。首先是一个annotation,这个不用说了吧。Assert类和Assume类。看了Assert类的代码,发现别人利用重载、泛型等技术使的代码的重用性非常高,举个例子看看:
/** * Asserts that two byte arrays are equal. If they are not, an * {@link AssertionError} is thrown with the given message. * * @param message * the identifying message for the {@link AssertionError} (<code>null</code> * okay) * @param expecteds * byte array with expected values. * @param actuals * byte array with actual values */ public static void assertArrayEquals(String message, byte[] expecteds, byte[] actuals) throws ArrayComparisonFailure { internalArrayEquals(message, expecteds, actuals); } /** * Asserts that two byte arrays are equal. If they are not, an * {@link AssertionError} is thrown. * * @param expecteds * byte array with expected values. * @param actuals * byte array with actual values */ public static void assertArrayEquals(byte[] expecteds, byte[] actuals) { assertArrayEquals(null, expecteds, actuals); } /** * Asserts that two char arrays are equal. If they are not, an * {@link AssertionError} is thrown with the given message. * * @param message * the identifying message for the {@link AssertionError} (<code>null</code> * okay) * @param expecteds * char array with expected values. * @param actuals * char array with actual values */ public static void assertArrayEquals(String message, char[] expecteds, char[] actuals) throws ArrayComparisonFailure { internalArrayEquals(message, expecteds, actuals); } /** * Asserts that two char arrays are equal. If they are not, an * {@link AssertionError} is thrown. * * @param expecteds * char array with expected values. * @param actuals * char array with actual values */ public static void assertArrayEquals(char[] expecteds, char[] actuals) { assertArrayEquals(null, expecteds, actuals); } /** * Asserts that two short arrays are equal. If they are not, an * {@link AssertionError} is thrown with the given message. * * @param message * the identifying message for the {@link AssertionError} (<code>null</code> * okay) * @param expecteds * short array with expected values. * @param actuals * short array with actual values */ public static void assertArrayEquals(String message, short[] expecteds, short[] actuals) throws ArrayComparisonFailure { internalArrayEquals(message, expecteds, actuals); }
可以看到,基本上都是调用了internalArrayEquals这个方法来实现的,这个方法接受了三个参数,而只有两个参数的判断数组相等,则使用了另外一个方法assertArrayEquals,我们来看看这个方法的实现:
public static void assertArrayEquals(String message, char[] expecteds, char[] actuals) throws ArrayComparisonFailure { internalArrayEquals(message, expecteds, actuals); }
可以看到里面同样是调用了internalArrayEquals方法,下面我们就来看看internalArrayEquals方法是怎么编写的:
private static void internalArrayEquals(String message, Object expecteds, Object actuals) throws ArrayComparisonFailure { new ExactComparisonCriteria().arrayEquals(message, expecteds, actuals); }
其内部调用了一个比较器中的数组比较方法,慢慢来,我们马上就要看到是怎么比较两个数组的了,当然,如果是浮点型的数据的话,它还可以传入一个精度,我们这里就不考虑了哦。
/** * Asserts that two arrays are equal, according to the criteria defined by * the concrete subclass. If they are not, an {@link AssertionError} is * thrown with the given message. If <code>expecteds</code> and * <code>actuals</code> are <code>null</code>, they are considered equal. * * @param message * the identifying message for the {@link AssertionError} ( * <code>null</code> okay) * @param expecteds * Object array or array of arrays (multi-dimensional array) with * expected values. * @param actuals * Object array or array of arrays (multi-dimensional array) with * actual values */ public void arrayEquals(String message, Object expecteds, Object actuals) throws ArrayComparisonFailure { if (expecteds == actuals) return; String header= message == null ? "" : message + ": "; int expectedsLength= assertArraysAreSameLength(expecteds, actuals, header); for (int i= 0; i < expectedsLength; i++) { Object expected= Array.get(expecteds, i); Object actual= Array.get(actuals, i); if (isArray(expected) && isArray(actual)) { try { arrayEquals(message, expected, actual); } catch (ArrayComparisonFailure e) { e.addDimension(i); throw e; } } else try { assertElementsEqual(expected, actual); } catch (AssertionError e) { throw new ArrayComparisonFailure(header, e, i); } } }
这个里面可以支持多维数组的比较,所以有一个递归的过程,并且首先调用AssertArraySameLength方法检查了一下数组的长度是否相等:
private int assertArraysAreSameLength(Object expecteds, Object actuals, String header) { if (expecteds == null) Assert.fail(header + "expected array was null"); if (actuals == null) Assert.fail(header + "actual array was null"); int actualsLength= Array.getLength(actuals); int expectedsLength= Array.getLength(expecteds); if (actualsLength != expectedsLength) Assert.fail(header + "array lengths differed, expected.length=" + expectedsLength + " actual.length=" + actualsLength); return expectedsLength; }
然后判断数组中的元素是不是还是数组,所以需要检查一下:
private boolean isArray(Object expected) { return expected != null && expected.getClass().isArray(); }
然后检查数组中的元素是否一一相等,使用到了
protected abstract void assertElementsEqual(Object expected, Object actual);
方法,可以看到这个方法是一个抽象方法,具体的实现是有子类来实现的,这种设计模式是将相同的部分抽象出来,不同的部分交给不同的子类来实现,其中spring中的jdbc封装类中都大量使用到了这种模式,这种模式叫做策略模式。
然后Assert的一些其他的方式类似什么AssertNotNull,AssertNotEquals等等,就非常简单了,这里就不介绍了。
Assume和其他的一些注解非常简单,这里就不一一演示了。