ImplementationCompatibilityTest

From APIDesign

Jump to: navigation, search

Very useful style of tests to ensure BackwardCompatibility when doing major rewrite of an implementation behind an API. Discussed in details in Chapter 15.

The basic idea consist of copying the original implementation of an API into the test and then performing various calls into the API twice (in the new and old implementation) and then ensuring the result is the same.

For an example see this style applied to old good Arithmetica class introduced in AlternativeBehaviour. Here is the copy of old implementation:

Code from ArithmeticaCompatibilityTest.java:
See the whole file.

/** This is a copy of the implementation of Arithmetica from version 1.0 */
static class OldArithmetica1 {
    public int sumTwo(int one, int second) {
        return one + second;
    }
 
    public int sumAll(int... numbers) {
        if (numbers.length == 0) {
            return 0;
        }
        int sum = numbers[0];
        for (int i = 1; i < numbers.length; i++) {
            sum = sumTwo(sum, numbers[i]);
        }
        return sum;
    }
 
    public int sumRange(int from, int to) {
        int len = to - from;
        int[] array = new int[len + 1];
        for (int i = 0; i <= len; i++) {
            array[i] = from + i;
        }
        return sumAll(array);
    }
} 
 

and here is a RandomizedTest to check the compatibility of new and old implementation:

Code from ArithmeticaCompatibilityTest.java:
See the whole file.

private void compare (Arithmetica now, OldArithmetica1 old, long seed) 
throws Exception {
    java.util.Random r = new java.util.Random (seed);
 
    for (int loop = 0; loop < r.nextInt(5); loop++) {
        int operation = r.nextInt(3);
        switch (operation) {
            case 0: { // sumTwo
                int a1 = r.nextInt(100);
                int a2 = r.nextInt(100);
                int resNow = now.sumTwo(a1, a2);
                int resOld = old.sumTwo(a1, a2);
                assertEquals("sumTwo results are equal", resNow, resOld);
                break;
            }
            case 1: { // sumArray
                int[] arr = new int[r.nextInt(100)];
                for (int i = 0; i < arr.length; i++) {
                    arr[i] = r.nextInt(100);
                }
                int resNow = now.sumAll(arr);
                int resOld = old.sumAll(arr);
                assertEquals("sumArray results are equal", resNow, resOld);
                break;
            }
            case 2: { // sumRange
                int a1 = r.nextInt(100);
                int a2 = r.nextInt(100);
                int resNow = now.sumRange(a1, a1 + a2);
                int resOld = old.sumRange(a1, a1 + a2);
                assertEquals("sumRange results are equal", resNow, resOld);
                break;
            }
        }
    }
}
 
Personal tools