Learn Object-Oriented Java the Hard Way

Exercise 10: Automated Testing with Arrays

Two exercises ago, SphereCalcTester did a decent job testing our object, but it took a lot of code for each test, and there was a lot of repeated code. It is important to make testing code as easy as possible to write and to automatically run. Otherwise, you might be tempted to not test your code, and that doesn’t lead anywhere good.

So here is an example of a tester for SphereCalc4 that makes it much easier to add additional tests without adding any extra code!

This code uses arrays of doubles to hold the expected inputs and outputs, and they are in the same order in each array so that areas[0] holds the expected area output for radius inputs[0] and volumes[0] holds the corresponding expected volume. Arrays used like this are called “parallel” arrays.

This isn’t the absolute best way to do this, but it’s good enough for now. We’ll see an even better testing technique later in the book.

BetterTesting.java
 1 public class BetterTesting {
 2     public static void main( String[] args ) {
 3 
 4         double[] inputs = {
 5             5,
 6             0.1,
 7             3.3,
 8             20000,
 9             8
10         };
11         double[] areas  = {
12             314.159265359,
13             0.125663706,
14             136.84777599,
15             5026548245.743669104,
16             804.247719319
17         };
18         double[] volumes = {
19             523.598775598,
20             4.18879E-3,
21             150.532553589,
22             3.3510321638291125E13,
23             2144.660584851
24         };
25         int passed = 0;
26         double r, a, v, A, V;
27 
28         SphereCalc4 c = new SphereCalc4(0);
29         for ( int i=0; i<inputs.length; i++ ) {
30             r = inputs[i];
31             a = areas[i];
32             v = volumes[i];
33 
34             c.setRadius(r);
35             A = c.getSurfaceArea();
36             V = c.getVolume();
37             if ( isNear(A, a) )
38                 passed++;
39             else {
40                 System.out.print("FAIL: surfaceArea for radius " + r );
41                 System.out.println("-- Expected " + a + ", got " + A);
42             }
43             if ( isNear(V, v) )
44                 passed++;
45             else {
46                 System.out.print("FAIL: volume for radius " + r );
47                 System.out.println("-- Expected " + v + ", got " + V);
48             }
49         }
50 
51         if ( passed == 2*inputs.length )
52             System.out.println("PASS: All tests passed.");
53     }
54 
55     public static boolean isNear( double a, double b ) {
56         return Math.abs(a-b) < 1E-9;
57     }
58 }

What You Should See

Lines 4 through 24 just contain the values for inputs and outputs. I like to list them one per line like this, but Java doesn’t care if you put them all on one line. If you do put them all on one line, it’d probably be good for your sanity if you add extra spaces so that the corresponding entries line up, like so:

double[] inputs  = {   5,           0.1,           3.3,         // etc
double[] areas   = { 314.159265359, 0.125663706, 136.84777599,  // etc
double[] volumes = { 523.598775598, 4.18879E-3,  150.532553589, // etc

On line 28 we just create a single SphereCalc4 object, which will be reused each time. Then there’s a loop through each value in the arrays. NOTE: If you accidentally make the arrays different lengths, then this code might blow up. That’s one of the problems with parallel arrays.

On lines 30 through 36 we pull out the expected radius, area and volume and put them into nicely-named but easy-to-type variables, and then tell the object to use that radius and get the computed area and volume from our object. So a is the expected area, and A is the actual area according to our object.

Then we can just use the same isNear() function from earlier together with if statements to see if what we got matches what was expected. We increment a variable for each “PASS” but don’t bother printing anything. If there’s a failure, we print an error message.

Once the loop is over, there should be twice as many “passes” as inputs, so we check that and print a summary message if everything is good.

Not too bad, huh? Adding more tests is as easy as just adding more numbers to the arrays, but none of the other code has to change. And it’s easy to tell when everything turned out as expected and easy to see specifically what went wrong when something isn’t right.


“Learn Object-Oriented Java the Hard Way” is ©2015–2016 Graham Mitchell