Chapter 8

Testing and Debugging


Chapter Goals

Unit Test

Root Approximator

File RootApproximator.java

1/**
2   Computes approximations to the square root of
3   a number, using Heron's algorithm
4*/
5public class RootApproximator
6{
7   /**
8      Constructs a root approximator for a given number
9      @param aNumber the number from which to extract the square root
10      (Precondition: aNumber >= 0)
11   */
12   public RootApproximator(double aNumber)
13   {
14      a = aNumber;
15      xold = 1;
16      xnew = a;
17   }
18
19   /**
20      Compute a better guess from the current guess.
21      @return the next guess
22   */
23   public double nextGuess()
24   {
25      xold = xnew;
26      if (xold != 0)
27         xnew = (xold + a / xold) / 2;
28      return xnew;
29   }
30
31   /**
32      Compute the root by repeatedly improving the current
33      guess until two successive guesses are approximately equal.
34      @return the computed value for the square root
35   */
36   public double getRoot()
37   {
38      while (!Numeric.approxEqual(xnew, xold))
39         nextGuess();
40      return xnew;
41   }
42   
43   private double a; // the number whose square root is computed
44   private double xnew; // the current guess
45   private double xold; // the old guess
46}

File RootApproximatorTest.java

1import javax.swing.JOptionPane;
2
3/**
4   This program prints ten approximations for a square root.
5*/
6public class RootApproximatorTest
7{  
8   public static void main(String[] args)
9   {  
10      String input 
11         = JOptionPane.showInputDialog("Enter a number");
12      double x = Double.parseDouble(input);
13      RootApproximator r = new RootApproximator(x);
14      final int MAX_TRIES = 10;
15      for (int tries = 1; tries <= MAX_TRIES; tries++)
16      {
17         double y = r.nextGuess();
18         System.out.println("Guess #" + tries + ": " + y);
19      }
20      System.exit(0);
21   }
22}

Unit Test with BlueJ


File RootApproximatorTest2.java

1import javax.swing.JOptionPane;
2
3/**
4   This program computes square roots of user-supplied inputs.
5*/
6public class RootApproximatorTest2
7{  
8   public static void main(String[] args)
9   {  
10      boolean done = false;
11      while (!done)
12      {  
13         String input = JOptionPane.showInputDialog(
14            "Enter a number, Cancel to quit");
15
16         if (input == null) 
17            done = true;
18         else
19         {  
20            double x = Double.parseDouble(input);
21            RootApproximator r = new RootApproximator(x);
22            double y = r.getRoot();
23            
24            System.out.println("square root of " + x
25               + " = " + y);
26         }
27      }
28      System.exit(0);
29   }
30}

Read Inputs from File

File RootApproximatorTest3.java

1import java.io.BufferedReader;
2import java.io.InputStreamReader;
3import java.io.IOException;
4
5/**
6   This program computes square roots of inputs supplied
7   through System.in
8*/
9public class RootApproximatorTest3
10{  
11   public static void main(String[] args)
12      throws IOException
13   {  
14      BufferedReader console 
15         = new BufferedReader(new InputStreamReader(System.in));
16      boolean done = false;
17      while (!done)
18      {  
19         String input = console.readLine();
20         if (input == null) done = true;
21         else
22         {  
23            double x = Double.parseDouble(input);
24            RootApproximator r = new RootApproximator(x);
25            double y = r.getRoot();
26            
27            System.out.println("square root of " + x
28               + " = " + y);
29         }
30      }
31   }
32}

Sources of Test Data

File RootApproximatorTest4.java

1/**
2   This program computes square roots of input values
3   supplied by a loop.
4*/
5public class RootApproximatorTest4
6{  
7   public static void main(String[] args)
8   {  
9      final double MIN = 1;
10      final double MAX = 10;
11      final double INCREMENT = 0.5;
12      for (double x = MIN; x <= MAX; x = x + INCREMENT)
13      {  
14         RootApproximator r = new RootApproximator(x);
15         double y = r.getRoot();
16         System.out.println("square root of " + x
17            + " = " + y);
18      }
19   }
20}

File RootApproximatorTest5.java

1import java.util.Random;
2
3/**
4   This program computes square roots of random inputs.
5*/
6public class RootApproximatorTest5
7{  
8   public static void main(String[] args)
9   {  
10      final double SAMPLES = 100;
11      Random generator = new Random();
12      for (int i = 1; i <= SAMPLES; i++)
13      {  // generate random test value
14
15         double x = 1.0E6 * generator.nextDouble();
16         RootApproximator r = new RootApproximator(x);
17         double y = r.getRoot();
18         System.out.println("square root of " + x
19            + " = " + y);
20      }
21   }
22}

Test Cases

Test Case Evaluation

File RootApproximatorTest6.java

1import java.util.Random;
2
3/**
4   This program verifies the computation of square root values
5   by checking a mathematical property of square roots.
6*/
7public class RootApproximatorTest6
8{  
9   public static void main(String[] args)
10   {  
11      final double SAMPLES = 100;
12      int passcount = 0;
13      int failcount = 0;
14      Random generator = new Random();
15      for (int i = 1; i <= SAMPLES; i++)
16      {  
17         // generate random test value
18
19         double x = 1.0E6 * generator.nextDouble();
20         RootApproximator r = new RootApproximator(x);
21         double y = r.getRoot();
22         System.out.println("square root of " + x
23            + " = " + y);
24
25         // check that test value fulfills square property
26
27         if (Numeric.approxEqual(y * y, x))
28         {
29            System.out.println("Test passed.");
30            passcount++;
31         }
32         else
33         {
34            System.out.println("Test failed.");
35            failcount++;
36         }
37      }
38      System.out.println("Pass: " + passcount);
39      System.out.println("Fail: " + failcount);
40   }
41}

File RootApproximatorTest7.java

1import java.util.Random;
2
3/**
4   This program verifies the computation of square root values
5   by using an oracle.
6*/
7public class RootApproximatorTest7
8{  
9   public static void main(String[] args)
10   {  
11      final double SAMPLES = 100;
12      int passcount = 0;
13      int failcount = 0;
14      Random generator = new Random();
15      for (int i = 1; i <= SAMPLES; i++)
16      {  
17         // generate random test value
18
19         double x = 1.0E6 * generator.nextDouble();
20         RootApproximator r = new RootApproximator(x);
21         double y = r.getRoot();
22         System.out.println("square root of " + x
23            + " = " + y);
24
25         double oracleValue = Math.pow(x, 0.5); 
26
27         // check that test value approximately equals oracle value
28
29         if (Numeric.approxEqual(y, oracleValue))
30         {
31            System.out.println("Test passed.");
32            passcount++;
33         }
34         else
35         {
36            System.out.println("Test failed.");
37            failcount++;
38         }
39      }
40      System.out.println("Pass: " + passcount);
41      System.out.println("Fail: " + failcount);
42   }
43}

Regression Testing

Test Coverage

Program Trace

Logging

Assertions

The Debugger

The Debugger Stopping at a Breakpoint


Inspecting Variables

 

Sample Debugging Session

File Word.java

1public class Word
2{
3   /**
4      Constructs a word by removing leading and trailing non-
5      letter characters, such as punctuation marks.
6      @param s the input string
7   */
8   public Word(String s)
9   {
10      int i = 0;
11      while (i < s.length() && !Character.isLetter(s.charAt(i)))
12         i++;
13      int j = s.length() - 1;
14      while (j > i && !Character.isLetter(s.charAt(j)))
15         j--;
16      text = s.substring(i, j + 1);      
17   }
18
19   /**
20      Returns the text of the word, after removal of the
21      leading and trailing non-letter characters.
22      @return the text of the word
23   */
24   public String getText()
25   {
26      return text;
27   }
28
29   /**
30      Counts the syllables in the word.
31      @return the syllable count
32   */
33   public int countSyllables()
34   {
35      int count = 0;
36      int end = text.length() - 1;
37      if (end < 0) return 0; // the empty string has no syllables
38
39      // an e at the end of the word doesn't count as a vowel
40      char ch = Character.toLowerCase(text.charAt(end));
41       if (ch == 'e') end--;
42
43      boolean insideVowelGroup = false;
44      for (int i = 0; i <= end; i++)
45      {
46         ch = Character.toLowerCase(text.charAt(i));
47         if ("aeiouy".indexOf(ch) >= 0) 
48         {
49            // ch is a vowel
50            if (!insideVowelGroup)
51            {
52               // start of new vowel group
53               count++; 
54               insideVowelGroup = true;
55            }
56         }
57         else
58            insideVowelGroup = false;
59      }
60
61      // every word has at least one syllable
62      if (count == 0) 
63         count = 1;
64
65      return count;      
66   }
67
68   private String text;
69}

File WordTest.java

1import java.util.StringTokenizer;
2import javax.swing.JOptionPane;
3
4public class WordTest
5{  
6   public static void main(String[] args)
7   {  
8      String input 
9         = JOptionPane.showInputDialog("Enter a sentence");
10      StringTokenizer tokenizer = new StringTokenizer(input);
11      while (tokenizer.hasMoreTokens())
12      {
13         String token = tokenizer.nextToken();         
14         Word w = new Word(token);
15         int syllables = w.countSyllables();
16         System.out.println("Syllables in " + w.getText() + ": " 
17            + syllables);
18      }
19      System.exit(0);
20   }
21}

Final Letter Test is Not Correct

Debugging the countSyllables Method

 

The Current Values of the Local and Instance Variables


 

More Problems Found

Debugging the Word Constructor

Debugging the Word Constructor

 

Another Error

Debugging countSyllables (again)

The First Bug


Therac-25 Facility