420 likes | 784 Views
FIT1002 Computer Programming Unit 19 Testing and Debugging. 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
E N D
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
Define the problem clearly • Analyze the problem • Design an algorithm • design top-down / implement bottom-up • Code (Implement) the algorithm • Test the code • Document the system Software Development Process
debugging and testing Development Cycle Analysis Design Implement Test
Debugging and Testing Debugging: the process of finding and correcting errors (a.k.a “bugs”) Testing: executing the program on a test data set
Types of Errors • syntactic: how instructions are written while (i=0; i < 5; i++) { j += i; } Example 1: • semantic: what they represent 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:
Example: BestMark • Problem: • Write a program which reads a list of marks, and prints out the best mark • Example: • Input:18 56 65 96 24 30 • Output:Best mark is 96
Example: BestMark (cont) Algorithm • 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
Classes of Test Data • Valid data • Valid boundary data • Special or unusual cases • Invalid data
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
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
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 • }
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”.
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
Flowcharts • Represent flow of control of algorithms: • sequences • selection • iteration • Useful for: • Finding semantic errors • Determining test data set
Flowchart: Sequence • Represented by concatenating instructions (usually vertically) Instruction in rectangular box Step A: input number Step B: add 1 to number Order of execution indicated by arrows Step C: output number
Step A: input number an algorithm involving “selection” Step C: output number Sequence (cont) • 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:
Step A NO YES C1 true? S1 S2 Step C Flowchart: Selection • Step A • if ( condition C1 ) • { • <sequence S1> • } • else • { • <sequence S2> • } • Step C Arrow labeled with result of condition test Condition test in diamond
input number is number negative? NO YES add -1 to number add 1 to number output number Example: Algorithm to Flowchart • input number • if number is negative, • then add -1 to number • else add 1 to number • output number
NO C1 true? YES S1 Flowchart: Iteration (while loop) • while ( condition C1 ) • { • <sequence S1> • }
init NO C1 true? YES S1 increment Flowchart: Iteration (for loop) for ( init ; condition C1 ; increment ) { <sequence S1> } has to be treated like a while loop…
set i to 0 is i < 10 ? NO YES input value for x increment i NO YES is x < 0 ? Example: Code to Flowchart (Spot the error!) for ( i=0; i<10; i++ ) { x=console.nextInt(); if ( x < 0 ) { break; } }
set i to 0 is i < 10 ? NO YES input value for x is x < 0 ? YES NO increment i Example: Code to Flowchart (correct version) for ( i=0; i<10; i++ ) { x=console.nextInt(); if ( x < 0 ) { break; } }
Algorithm to FlowchartExample: 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
Algorithm to FlowchartExample: 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 is count< totalNumbers? NO YES input value for nextNum add nextNum to sum increment count
Algorithm to FlowchartExample: 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
Testing All Execution Paths 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"); x>2? x>y? x<y? output S1 output S3 output S2 decrement x output S4
Example (cont) 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"); YES NO x>2?
Example (cont) 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"); NO YES x>2? NO x>y? YES output S1 decrement x
Example (cont) 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"); NO YES x>2? NO NO x>y? x<y? YES YES output S1 output S3 decrement x
Example (cont) 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"); NO YES x>2? NO NO x>y? x<y? YES YES output S1 output S3 output S2 decrement x output S4
Testing all logical execution paths • What is done for every input? 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"); • What does this say about the output? • S4 must be output at the end every time
NO Input x,y YES x>2? NO NO x>y? x<y? YES YES output S1 output S3 output S2 decrement x output S4 Example (cont): Choice Points Paths are determined by choice points
NO Input x,y YES x>2? NO NO x>y? x<y? YES YES output S1 output S3 output S2 decrement x output S4 Test data for all logical paths
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.
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
Example: Debugging Statements (cont) … 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); } TIP: make debugging statements conditional on a boolean variable
Assertions (advanced, optional) • 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 … assert n%k==0; …
Typical Bugs Array index out of bounds (Array out of bounds exception) Object variables and arrays unititalized (null pointer exception) Infinite loops (termination condition wrong) Incorrect boolean expressions (operator precedences) Incorrect nesting of selection (dangling else)
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.
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