一直听说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和其他的一些注解非常简单,这里就不一一演示了。