FIT FIT1002 Computer Programming Unit 19 Testing and Debugging
FIT Objectives By the end of this lecture, students should: understand how to perform basic testing of a program understand how to apply a flow chart to determine test cases understand the concept of interactive source-level debugging design a simple test strategy use the debugger in BlueJ
FIT Software Development Process Define the problem clearly Analyze the problem Design an algorithm design top-down / implement bottom-up Document the system Code (Implement) the algorithm Test the code
FIT Development Cycle AnalysisDesignImplementTest debugging and testing
FIT Debugging and Testing Debugging: the process of finding and correcting errors (a.k.a “bugs”) Testing: executing the program on a test data set
FIT Types of Errors syntactic: how instructions are written semantic: what they represent while (i=0; i < 5; i++) { j += i; } Example 1: n=0; …; n=6; … for (i=n; i != 5; i++) { System.out.println(i); } Example 2: if (choice == ‘Q’) { throw new Error(); return 0; } Example 3:
FIT Example: BestMark Problem: Write a program which reads a list of marks, and prints out the best mark Example: Input: Output: Best mark is 96
FIT Example: BestMark (cont) set bestMark to 0 loop { input mark if (end of input) then exit loop if (mark > bestMark) then { set bestMark to mark } output “Best mark is “, bestMark Algorithm
FIT Classes of Test Data 1. Valid data 2. Valid boundary data 3. Special or unusual cases 4. Invalid data
FIT Test Data: Valid Data Reasonable data for the problem Example: BestMark What is the test out of? If mark is out of 100, valid test data is 75, 65, 55
FIT Test Data: Valid Boundary Data Data with extreme values Example: BestMark minimum of 0 maximum of 100 Particularly use test data to: – Test iteration exit conditions – Test first and last elements of an array
FIT Test Data: Special Cases Example: BestMark What if someone is absent or the mark is withheld (special consideration)? input markEntered if (markEntered is “Abs” or “WH”) { output “No mark for this student” set mark to 0 } else { set mark to numerical value of markEntered }
FIT Test Data: Invalid Data Invalid data is of an incorrect type/class, or outside the expected range or not adhering to some other constraint on the data (eg, a String for a name containing special characters) Use data types in your program as restrictively as possible to make sure that such problems are automatically avoided. For example, it is much better to code the mark as an object with an instance variable of type int and a boolean field “withheld” instead of using a string to code a mark that could potentially be a “WH”.
FIT Testing Techniques Test data set should “fully” test the program All logical paths of the program should be traversed (i.e., every line of code should be executed at least once) Use the design represented by the flowchart TIP: build your programs incrementally, testing small components as you go along
FIT Flowcharts Represent flow of control of algorithms: sequences selection iteration Useful for: Finding semantic errors Determining test data set
FIT Flowchart: Sequence Step A: input number Step B: add 1 to number Step C: output number Instruction in rectangular box Order of execution indicated by arrows Represented by concatenating instructions (usually vertically)
FIT Step A: input number Step B: if number is negative, then add -1 to number else add 1 to number Step C: output number Example 2: an algorithm involving “selection” Step A: input number Step C: output number Sequence (cont)
FIT Flowchart: Selection Step A if ( condition C1 ) { } else { } Step C Step A C1 true? S2 Step C S1 YES NO Arrow labeled with result of condition test Condition test in diamond
FIT input number if number is negative, then add -1 to number else add 1 to number output number input number is number negative? add -1 to number YES NO add 1 to number output number Example: Algorithm to Flowchart
FIT Flowchart: Iteration (while loop) while ( condition C1 ) { } C1 true? S1 YES NO
FIT Flowchart: Iteration (for loop) for ( init ; condition C1 ; increment ) { } has to be treated like a while loop… C1 true? S1 YES NO init increment
FIT Example: Code to Flowchart (Spot the error!) for ( i=0; i<10; i++ ) { x=console.nextInt(); if ( x < 0 ) { break; } is i < 10 ? input value for x YES NO set i to 0 increment i is x < 0 ? NOYES
FIT Example: Code to Flowchart (correct version) for ( i=0; i<10; i++ ) { x=console.nextInt(); if ( x < 0 ) { break; } is i < 10 ? input value for x YES NO set i to 0 increment i is x < 0 ? NO YES
FIT Algorithm to Flowchart Example: Calculating Mean input totalNumbers set sum to 0 set count to 0 while (count < totalNumbers) { input nextNum add nextNum to sum add 1 to count } output “Sum was” sum output “Mean was” sum/count input value for totalNumbers set sum to 0 set count to 0
FIT is count< totalNumbers? Algorithm to Flowchart Example: Calculating Mean input totalNumbers set sum to 0 set count to 0 while (count < totalNumbers) { input nextNum add nextNum to sum add 1 to count } output “Sum was” sum output “Mean was” sum/count input value for nextNum YES NO increment count add nextNum to sum
FIT Algorithm to Flowchart Example: Calculating Mean input totalNumbers set sum to 0 set count to 0 while (count < totalNumbers) { input nextNum add nextNum to sum add 1 to count } output “Sum was” sum output “Mean was” sum/count output value for sum output value for sum/count
FIT Testing All Execution Paths int x; int y; x=console.nextInt(); y=console.nextInt(); if (x > 2) { while (x > y) { System.out.println("S1,"); x--; } System.out.println("S2,"); } else if (x < y) { System.out.println("S3,"); } System.out.println("S4"); x>2? Input x,y output S2 x<y? output S4 output S3 x>y? output S1 decrement x
FIT Example (cont) YESNO x>2? Input x,y int x; int y; x=console.nextInt(); y=console.nextInt(); if (x > 2) { while (x > y) { System.out.println("S1,"); x--; } System.out.println("S2,"); } else if (x < y) { System.out.println("S3,"); } System.out.println("S4");
FIT Example (cont) int x; int y; x=console.nextInt(); y=console.nextInt(); if (x > 2) { while (x > y) { System.out.println("S1,"); x--; } System.out.println("S2,"); } else if (x < y) { System.out.println("S3,"); } System.out.println("S4"); x>2? Input x,y x>y? output S1 decrement x YES NO YES
FIT Example (cont) int x; int y; x=console.nextInt(); y=console.nextInt(); if (x > 2) { while (x > y) { System.out.println("S1,"); x--; } System.out.println("S2,"); } else if (x < y) { System.out.println("S3,"); } System.out.println("S4"); YES NO x>2? Input x,y NO YES NO YES x>y? output S1 decrement x x<y? output S3
FIT YES NO x>2? Input x,y NO output S2 x<y? output S4 YES output S3 NO YES x>y? output S1 decrement x Example (cont) int x; int y; x=console.nextInt(); y=console.nextInt(); if (x > 2) { while (x > y) { System.out.println("S1,"); x--; } System.out.println("S2,"); } else if (x < y) { System.out.println("S3,"); } System.out.println("S4");
FIT Testing all logical execution paths What is done for every input? What does this say about the output? S4 must be output at the end every time int x; int y; x=console.nextInt(); y=console.nextInt(); if (x > 2) { while (x > y) { System.out.println("S1,"); x--; } System.out.println("S2,"); } else if (x < y) { System.out.println("S3,"); } System.out.println("S4");
FIT Example (cont): Choice Points YES NO x>2? Input x,y NO output S2 x<y? output S4 YES output S3 NO YES x>y? output S1 decrement x Paths are determined by choice points
FIT Test data for all logical paths YES NO x>2? Input x,y NO output S2 x<y? output S4 output S3 NO YES x>y? output S1 decrement x xy
FIT Debugging Testing is the process of checking whether the program behaves as expected. If it does not behave as expected we need to find the mistakes and remove them. This process is called debugging. The fundamental process of debugging is to make assumptions about what the state of the program should be at some intermediate point and to verify whether this is the case. This allows us to narrow down to the point where the problem originates.
FIT Example: Debugging Statements... for (i=n; i!=2*n; i+=k) { System.out.println(a[i]); } If this loop does not terminate correctly, we need to verify that i really reaches the value 2n, i.e. that n is divisible by k (assumption). Approach 1: Embed printing statements to check this
FIT Example: Debugging Statements (cont) TIP: make debugging statements conditional on a boolean variable … final boolean debugging = true; … if (debugging) System.out.println(“n=“+n+” k=“+k); for (i=n; i!=2*n; i+=k) { System.out.println(a[i]); if (debugging) System.out.println(“i=“+i+” k=“+k); }
FIT Assertions (advanced, optional) … assert n%k==0; … Java has a special mechanism to verify assumptions like “n is divisible by k” above called “assertions”. you “assert” a boolean condition Java checks this condition every time the assertion is encountered. If the condition is true nothing happens if it is false, an exception is thrown (and the program is terminated) You need to run your program from the command line with assertions enabled to use this checking mechanism: java -cp. -enableassertions MyProg
FIT Typical Bugs 1. Array index out of bounds (Array out of bounds exception) 2. Object variables and arrays unititalized (null pointer exception) 3. Infinite loops (termination condition wrong) 4. Incorrect boolean expressions (operator precedences) 5. Incorrect nesting of selection (dangling else)
FIT Source-Level Debugging Luckily modern interactive development environments offer much more comfortable means of debugging. In particular, they can indicate the current location of the execution in the source code. This is called source-level debugging. Details differ between IDEs. We will demonstrate source- level debugging in BlueJ interactively in the tutorials. Details of the BlueJ debugger can be found in the BlueJ manuals.
FIT Tracing The process of executing a program step by step and checking its state is called tracing. The debugger –indicates current execution point in the source code –allows to inspect current contents of variables –allows to inspect current state of objects You can set “breakpoints” on source-code statements. The trace can be performed –“stepping” from statement to statement or – “skipping” from breakpoint to breakpoint
FIT BlueJ Debugger