Download presentation
Presentation is loading. Please wait.
Published byLucinda Gallagher Modified over 9 years ago
1
Chapter 10 Testing and Debugging
2
Chapter Goals ► To learn how to carry out unit tests ► To understand the principles of test case selection and evaluation ► To learn how to use logging ► To become familiar with the debugger ► To learn strategies for effective debugging
3
The First Bug
4
Unit Test Test classes in isolation, outside the program in which they are used Test one class at a time Supply test inputs through test harness Test harness = program that feeds test inputs to a class
5
Root Approximator ► Example program to illustrate testing: square root approximator Algorithm known to the ancient Greeks (Heron) ► Task: to compute the square root of a ► Given: a guess x (we start with x=a) The actual square root lies between a/x and x
6
► Take midpoint (x + a/x) / 2 as a better guess Method converges rapidly. ► Square root of 100: Guess #1: 50.5 Guess #2: 26.24009900990099 Guess #3: 15.025530119986813 Guess #4: 10.840434673026925 Guess #5: 10.032578510960604 Guess #6: 10.000052895642693 Guess #7: 10.000000000139897 Guess #8: 10.0 All the other guesses from this point on, return the same value
7
File RootApproximator.java 1 /** 2 Computes approximations to the square root 3 of a number, using Heron's algorithm 4 */ 5 public 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 {a = aNumber; 15 xold = 1; 16 xnew = a; 17 }
8
18 19 /** 20 Compute a better guess from the current guess. 21 @return the next guess 22 */ 23 public double nextGuess() 24 { xold = xnew; 26 if (xold != 0) 27 xnew = (xold + a / xold) / 2; 28 return xnew; 29 } 30
9
31 /** 32 Compute the root by repeatedly improving 33 the current 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 }
10
File RootApproximatorTest.java 1 import javax.swing.JOptionPane; 2 /** This program prints ten approximations for a square root. 3 */ 4 public class RootApproximatorTest 5 { 6 public static void main(String[] args) 7 { 8 String input = JOptionPane.showInputDialog("Enter a number"); 9 double x = Double.parseDouble(input); 10 RootApproximator r = new RootApproximator(x); 11 final int MAX_TRIES = 10; 12 for (int tries = 1; tries <= MAX_TRIES; tries++) 13{ double y = r.nextGuess(); 14 System.out.println("Guess #" + tries + ": " + y); 15 } 16 System.exit(0); 17 } 18 }
11
Unit Test with BlueJ
12
File RootApproximatorTest2 1 import javax.swing.JOptionPane; 2 /** This program computes square roots of user-supplied inputs. 3 */ 4 public class RootApproximatorTest2 5 { public static void main(String[] args) 6 { 7 boolean done = false; 8 while (!done) 9 { String input = JOptionPane.showInputDialog("Enter a number, C to quit"); 10 if (input == null) 12 done = true; 13 else 14 { double x = Double.parseDouble(input); 16 RootApproximator r = new RootApproximator(x); 17 double y = r.getRoot(); 18 System.out.println("square root of " + x + " = " + y); 20 } 21 } 22 System.exit(0); 23 } 24 }
13
Sources of Test Data ► Provided by humans RootApproximatorTest2 ► Computer-generated sequence RootApproximatorTest3 ► Random sequence RootApproximatorTest4
14
File RootApproximatorTest3.java 1 /** This program computes square roots of input values 2 computer generated by a loop. */ 3 public class RootApproximatorTest3 4 { public static void main(String[] args) 5 { 6 final double MIN = 1; 7final double MAX = 10; 8 final double INCREMENT = 0.5; 9 for (double x = MIN; x <= MAX; x = x + INCREMENT) 10 { 11 RootApproximator r = new RootApproximator(x); 12 double y = r.getRoot(); 13 System.out.println("square root of " + x + " = " + y); 14 } } }
15
File RootApproximatorTest4.java 1 import java.util.Random; 2 /** This program computes square roots of random inputs. */ 3 public class RootApproximatorTest4 4 { public static void main(String[] args) 5 { final double SAMPLES = 100; 6 Random generator = new Random(); 7 for (int i = 1; i <= SAMPLES; i++) 8 { // generate random test value 9 double x = 1.0E6 * generator.nextDouble(); 10 RootApproximator r = new RootApproximator(x); 11 double y = r.getRoot(); 12 System.out.println("square root of " + x + " = " + y); 13 } 14 } 15 }
16
Test Cases Positive test case: expect positive outcome E.g. square root of 100 Negative test case: expect negative outcome E.g. square root of 100 Boundary test case: at boundary of domain Frequent cause for errors E.g. square root of 0
17
Test Case Evaluation Manual E.g. You know the result and you verify if the program has produced the correct result Check property of result E.g. square root squared = original value Oracle = slower way of computing answer E.g. square root of x = x 1/2
18
Regression Testing ► Save test cases Automate testing ► java Program test1.out java Program test2.out java Program test3.out ► Repeat test whenever program changes Test suite = collection of test cases Cycling = bug that is fixed but reappears in later version Regression testing = testing against past failures
19
Test Coverage ► Black-box testing: test functionality without understanding internal structure ► White-box testing: take internal structure into account when designing tests ► Test coverage: the code that is actually executed during test cases ► Easy to overlook error branches during testing Make sure to execute each branch in at least one test case
20
Program Trace Output statements in your program for diagnostic purposes if (status == SINGLE) { System.out.println("status is SINGLE");... }...
21
Logging 1.Get global logger object: Logger logger = Logger.getLogger("global"); 2.Log a message logger.info("status is SINGLE"); 3.By default, logged messages are printed. Turn them off with logger.setLevel(Level.OFF); Remember to import java.util.logging.Logger
22
The Debugger Debugger = program to run your program, interrupt it, and inspect variables Three key commands: Set Breakpoint Single Step Inspect Variable Two variations of Single Step Step Over = don't enter method call Step Inside = enter method call
23
The Debugger Stopping at a Breakpoint
24
Inspecting Variables
25
Sample Debugging Session Word class counts syllables in a word Each group of adjacent vowels (aeiouy) is a syllable However, an e at the end of a word doesn't count If algorithm gives count of 0, increment to 1 Constructor removes non-letters at beginning and end Buggy output: Syllables in hello: 1 Syllables in regal: 1 Syllables in real: 1
26
File Word.java 1 public class Word 2 { 3 /** Constructs a word by removing leading and trailing 4 non-letter characters, such as punctuation marks. 5 @param s the input string */ 6 public Word(String s) 7 { int i = 0; 8 while (i < s.length() && !Character.isLetter(s.charAt(i))) 9 i++; 10 int j = s.length() - 1; 11 while (j > i && !Character.isLetter(s.charAt(j))) 12 j--; 13 text = s.substring(i, j + 1); 14 } 15
27
16 /** Returns the text of the word, after removal of 17 the leading and trailing non-letter characters. 18 @return the text of the word */ 19 public String getText() 20 { return text; } 21 22 /** Counts the syllables in the word. 23 @return the syllable count */ 24 public int countSyllables() 25 { int count = 0; 26 int end = text.length() - 1; 27 if (end < 0) return 0; // the empty string has no syllables 28 29 // An e at the end of the word doesn't count as a vowel 30 char ch = Character.toLowerCase(text.charAt(end)); 31 if (ch == 'e') end--;
28
32 boolean insideVowelGroup = false; 33 for (int i = 0; i <= end; i++) 34 { ch = Character.toLowerCase(text.charAt(i)); 35 if ("aeiouy".indexOf(ch) >= 0) 36 { // ch is a vowel 37 if (!insideVowelGroup) 38 { // start of new vowel group 39 count++; 40 insideVowelGroup = true; 41 } 42 } 43 44 // Every word has at least one syllable 45 if (count == 0) 46 count = 1; 47 return count; 48 } 49 private String text; 50 }
29
File WordTest.java 1 import java.util.StringTokenizer; 2 import javax.swing.JOptionPane; 3 public class WordTest 4 { public static void main(String[] args) 5 { 6 String input = JOptionPane.showInputDialog("Enter a sentence"); 7 StringTokenizer tokenizer = new StringTokenizer(input); 8 while (tokenizer.hasMoreTokens()) 9 { 10 String token = tokenizer.nextToken(); 11 Word w = new Word(token); 12 int syllables = w.countSyllables(); 13 System.out.println("Syllables in " + w.getText() + ": " + syllables); 14 } 15 System.exit(0); 16 } }
30
Final Letter Test is Not Correct Set breakpoint in line 35 (first line of countSyllables) Start program, supply input hello Method checks if final letter is 'e' Run to line 41 Inspect variable ch Should contain final letter but contains 'l'
31
Debugging the countSyllables Method
32
The Current Values of the Local and Instance Variables
33
More Problems Found end is set to 3, not 4 text contains "hell", not "hello" No wonder countSyllables returns 1 Culprit is elsewhere Can't go back in time Restart and set breakpoint in Word constructor
34
Debugging the Word Constructor Supply "hello" input again Break past the end of second loop in constructor Inspect i and j They are 0 and 4--makes sense since the input consists of letters Why is text set to "hell"? Off-by-one error: Second parameter of substring is the first position not to include text = substring(i, j); should be text = substring(i, j + 1);
35
Debugging the Word Constructor
36
Another Error Fix the error Recompile Test again: Syllables in hello: 1 Syllables in regal: 1 Syllables in real: 1 Oh no, it's still not right Start debugger Erase all old breakpoints Supply input "regal"
37
Debugging countSyllables (again) Break in the beginning of countSyllables Single-step through loop First iteration ('r'): skips test for vowel Second iteration ('e'): passes test, increments count Third iteration ('g'): skips test Fourth iteration ('a'): passes test, but doesn't increment count insideVowelGroup was never reset to false Fix and retest: All test cases pass Is the program now bug-free? The debugger can't answer that.
Similar presentations
© 2025 SlidePlayer.com. Inc.
All rights reserved.