Software Verification

Slides:



Advertisements
Similar presentations
Graph Coverage for Design Elements 1.  Use of data abstraction and object oriented software has increased importance on modularity and reuse.  Therefore.
Advertisements

The Application of Graph Criteria: Source Code  It is usually defined with the control flow graph (CFG)  Node coverage is used to execute every statement.
CMSC 345, Version 11/07 SD Vick from S. Mitchell Software Testing.
Road Map Introduction to object oriented programming. Classes
OOP in Java Nelson Padua-Perez Chau-Wen Tseng Department of Computer Science University of Maryland, College Park.
Software Testing Verification and validation planning Software inspections Software Inspection vs. Testing Automated static analysis Cleanroom software.
“is a”  Define a new class DerivedClass which extends BaseClass class BaseClass { // class contents } class DerivedClass : BaseClass { // class.
Introduction to Software Testing Chapter 1 Introduction Paul Ammann & Jeff Offutt
Introduction to Software Testing Chapter 2.3 Graph Coverage for Source Code Paul Ammann & Jeff Offutt
Paul Ammann & Jeff Offutt
Introduction to Software Testing Chapter 2.4 Graph Coverage for Design Elements Paul Ammann & Jeff Offutt
Introduction to Software Testing Chapter 7.1 Engineering Criteria for Technologies Paul Ammann & Jeff Offutt
Introduction to Object Oriented Programming. Object Oriented Programming Technique used to develop programs revolving around the real world entities In.
Software Testing and Maintenance Lecture 4 Graph Coverage for Design Element Paul Ammann & Jeff Offutt Instructor: Hossein Momeni Mazandaran.
APCS Java AB 2004 Review of CS1 and CS2 Review for AP test #1 Sources: 2003 Workshop notes from Chris Nevison (Colgate University) AP Study Guide to go.
Hello.java Program Output 1 public class Hello { 2 public static void main( String [] args ) 3 { 4 System.out.println( “Hello!" ); 5 } // end method main.
©Ian Sommerville 2004Software Engineering, 7th edition. Chapter 22 Slide 1 Software Verification, Validation and Testing.
Software Testing Reference: Software Engineering, Ian Sommerville, 6 th edition, Chapter 20.
1 Graph Coverage (4). Reading Assignment P. Ammann and J. Offutt “Introduction to Software Testing” ◦ Section
CSC 480 Software Engineering Lecture 15 Oct 21, 2002.
Software Verification Graph Model 2. 2 Graph Coverage Four Structures for Modeling Software Graphs Logic Input Space Syntax Use cases Specs Design Source.
Introduction to Software Testing Chapter 2.3 Graph Coverage for Source Code Paul Ammann & Jeff Offutt
Software Verification Graph Model. 2 Graph Coverage Four Structures for Modeling Software Graphs Logic Input Space Syntax Use cases Specs Design Source.
Paul Ammann & Jeff Offutt
Introduction to Software Testing (2nd edition) Chapter 7.4 Graph Coverage for Design Elements Paul Ammann & Jeff Offutt
Introduction to Software Testing Chapter 2.3 Graph Coverage for Source Code Paul Ammann & Jeff Offutt.
Introduction to Software Testing Chapter 7.1 Engineering Criteria for Technologies Paul Ammann & Jeff Offutt
Software Engineering1  Verification: The software should conform to its specification  Validation: The software should do what the user really requires.
Graph Coverage for Design Elements 1.  Use of data abstraction and object oriented software has increased importance on modularity and reuse.  Therefore.
1 Graph Coverage (3). Reading Assignment P. Ammann and J. Offutt “Introduction to Software Testing” ◦ Section 2.2 ◦ Section
Control Flow Graphs : The if Statement 1 if (x < y) { y = 0; x = x + 1; } else { x = y; } x >= yx < y x = y y = 0 x = x + 1 if (x < y) { y = 0;
Data Flow Coverage Criteria
Software Testing and Maintenance Lecture 3 Graph Coverage for Source Code Paul Ammann & Jeff Offutt Instructor: Hossein Momeni Mazandaran.
Data Flow Testing. Introduction to Software Testing (Ch 2) © Ammann & Offutt 2 Definition of a Graph A set N of nodes, N is not empty A set N 0 of initial.
Software Testing Reference: Software Engineering, Ian Sommerville, 6 th edition, Chapter 20.
Chapter 2 : Graph Coverage (part 2)
Paul Ammann & Jeff Offutt
Lab 7 Control-Flow Testing
Modern Programming Tools And Techniques-I
Paul Ammann & Jeff Offutt
Testing Object-Oriented Software Test Coverage Criteria
Paul Ammann & Jeff Offutt
Chapter 13: Pointers, Classes, Virtual Functions, and Abstract Classes
Software Testing and Maintenance 1
Paul Ammann & Jeff Offutt
Introduction to Software Testing Syntactic Logic Coverage Criteria
Inheritance and Polymorphism
Paul Ammann & Jeff Offutt
Input Space Partition Testing CS 4501 / 6501 Software Testing
Graph Coverage for Specifications CS 4501 / 6501 Software Testing
Testing Object-Oriented Software Concepts and Definitions
Paul Ammann & Jeff Offutt
Programming Language Concepts (CIS 635)
Path testing Path testing is a “design structural testing” in that it is based on detailed design & the source code of the program to be tested. The.
Graph Coverage for Design Elements CS 4501 / 6501 Software Testing
Paul Ammann & Jeff Offutt
Paul Ammann & Jeff Offutt
Paul Ammann & Jeff Offutt
Paul Ammann & Jeff Offutt
Software testing.
Paul Ammann & Jeff Offutt
Graph Coverage for Design Elements CS 4501 / 6501 Software Testing
Graph Coverage for Specifications CS 4501 / 6501 Software Testing
Graph Coverage for Source Code
Paul Ammann & Jeff Offutt
Paul Ammann & Jeff Offutt
Tata Consultancy Services
COSC 4506/ITEC 3506 Software Engineering
Paul Ammann & Jeff Offutt
Paul Ammann & Jeff Offutt
Presentation transcript:

Software Verification Graph Model 2

Model-Driven Test Design – Activities refined requirements / test specs Test Design model / structure test requirements DESIGN ABSTRACTION LEVEL IMPLEMENTATION ABSTRACTION LEVEL software artifact input values Test Automation Test Evaluation pass / fail test results Test Execution test scripts test cases

Embed test values into executable scripts 2. Test Automation Embed test values into executable scripts This is slightly less technical Requires knowledge of programming Fairly straightforward programming – small pieces and simple algorithms Programming is out of reach for many domain experts

3. Test Execution 4. Test Evaluation Run tests on the software and record the results This is easy – and trivial if the tests are well automated 4. Test Evaluation Evaluate results of testing, report to developers This is much harder than it may seem

Testing : Finding inputs that cause the software to fail Testing & Debugging Testing : Finding inputs that cause the software to fail Debugging : The process of finding a fault given a failure

Static and Dynamic Testing Static Testing : Testing without executing the program This include software inspections and some forms of analyses Very effective at finding certain kinds of problems – especially “potential” faults, that is, problems that could lead to faults when the program is modified Dynamic Testing : Testing by executing the program with real inputs

Stress testing Exercises the system beyond its maximum design load. Stressing the system often causes defects to come to light Stressing the system test faulure behaviour.. Systems should not fail catastrophically. Stress testing checks for unacceptable loss of service or data Particularly relevant to distributed systems which can exhibit severe degradation as a network becomes overloaded

Tests that are at the limit of the software’s expected input domain Stress Testing Tests that are at the limit of the software’s expected input domain Very large numeric values (or very small) Very long strings, empty strings Null references Very large files Many users making requests at the same time Invalid values

Back-to-back testing Present the same tests to different versions of the system and compare outputs. Differing outputs imply potential problems Reduces the costs of examining test results. Automatic comparison of outputs. Possible to when a prototype is available or with regression testing of a new system version

Performance testing Does it meet requirements? Test for performance behavior Does it meet requirements? Customer requirements Definitional requirements (e.g. Ethernet) Test for resource utilization Understand resource requirements Test performance early Avoid costly redesign to meet performance requirements

Security Testing Example: denial of service Example: network topology Is data/access safe from those who should not have it? Is data/access available to those who should have it? How is privilege granted/revoked? Is the system safe from unauthorized control? Example: denial of service Collateral data that compromises security Example: network topology

Test Case Test Case Values : The values that directly satisfy one test requirement Expected Results : The result that will be produced when executing the test if the program satisfies it intended behavior

Models for Quality in Software CMMI-SW ISO 9001:2000 ISO 90003 TickIt Six Sigma Plan, Do, Check, Act (PCDA)

Data Flow Test Criteria First, we make sure every def reaches a use All-defs coverage (ADC) : For each set of du-paths S = du (n, v), TR contains at least one path d in S. Then we make sure that every def reaches all possible uses All-uses coverage (AUC) : For each set of du-paths to uses S = du (ni, nj, v), TR contains at least one path d in S. Finally, we cover all the paths between defs and uses All-du-paths coverage (ADUPC) : For each set S = du (ni, nj, v), TR contains every path d in S.

Data Flow Testing Example 2 1 6 3 5 4 X = 42 Z = X-8 Z = X*2 All-defs for X [ 0, 1, 3, 4 ] All-uses for X [ 0, 1, 3, 4 ] [ 0, 1, 3, 5 ] All-du-paths for X [ 0, 1, 3, 4 ] [ 0, 2, 3, 4 ] [ 0, 1, 3, 5 ] [ 0, 2, 3, 5 ]

Example: Definition and Uses What are the definitions and uses for the program below? 1. read (x, y); 2. z = x + 2; 3. if (z < y) 4 w = x + 1; else 5. y = y + 1; 6. print (x, y, w, z);

Example: Definition and Uses x, y z x z, y w y x, y, w, z 1. read (x, y); 2. z = x + 2; 3. if (z < y) 4 w = x + 1; else y = y + 1; 6. print (x, y, w, z);

Example Data Flow – Stats public static void computeStats (int [ ] numbers) { int length = numbers.length; double med, var, sd, mean, sum, varsum; sum = 0.0; for (int i = 0; i < length; i++) sum += numbers [ i ]; } med = numbers [ length / 2 ]; mean = sum / (double) length; varsum = 0.o; varsum = varsum + ((numbers [ i ] - mean) * (numbers [ i ] - mean)); var = varsum / ( length - 1 ); sd = Math.sqrt ( var ); System.out.println ("length: " + length); System.out.println ("mean: " + mean); System.out.println ("median: " + med); System.out.println ("variance: " + var); System.out.println ("standard deviation: " + sd);

Control Flow Graph for Stats public static void computeStats (int [ ] numbers) { int length = numbers.length; double med, var, sd, mean, sum, varsum; sum = 0.0; for (int i = 0; i < length; i++) sum += numbers [ i ]; } med = numbers [ length / 2 ]; mean = sum / (double) length; varsum = 0.o; varsum = varsum + ((numbers [ i ] - mean) * (numbers [ i ] - mean)); var = varsum / ( length - 1 ); sd = Math.sqrt ( var ); System.out.println ("length: " + length); System.out.println ("mean: " + mean); System.out.println ("median: " + med); System.out.println ("variance: " + var); System.out.println ("standard deviation: " + sd); 8 1 2 4 3 5 6 7 ( numbers ) sum = 0 length = numbers.length i = 0 i >= length i < length med = numbers [ length / 2 ] mean = sum / (double) length varsum = 0 i = 0 sum += numbers [ i ] i++ i >= length i < length var = varsum / ( length - 1.0 ) sd = Math.sqrt ( var ) print (length, mean, med, var, sd) varsum = … i++

CFG for Stats – With Defs & Uses 8 1 2 4 3 5 6 7 def (1) = { numbers, sum, length } def (2) = { i } use (3, 5) = { i, length } use (3, 4) = { i, length } def (5) = { med, mean, varsum, i } use (5) = { numbers, length, sum } def (4) = { sum, i } use (4) = { sum, numbers, i } use (6, 8) = { i, length } use (6, 7) = { i, length } def (8) = { var, sd } use (8) = { varsum, length, mean, med, var, sd } def (7) = { varsum, i } use (7) = { varsum, numbers, i, mean }

Defs and Uses Tables for Stats Node Def Use 1 { numbers, sum, length } { numbers } 2 { i } 3 4 { sum, i } { numbers, i, sum } 5 { med, mean, varsum, i } { numbers, length, sum } 6 7 { varsum, i } { varsum, numbers, i, mean } 8 { var, sd } { varsum, length, var, mean, med, var, sd } Edge Use (1, 2) (2, 3) (3, 4) { i, length } (4, 3) (3, 5) (5, 6) (6, 7) (7, 6) (6, 8)

DU Pairs for Stats defs come before uses, do not count as DU pairs variable DU Pairs numbers (1, 4) (1, 5) (1, 7) length (1, 5) (1, 8) (1, (3,4)) (1, (3,5)) (1, (6,7)) (1, (6,8)) med (5, 8) var (8, 8) sd mean (5, 7) (5, 8) sum (1, 4) (1, 5) (4, 4) (4, 5) varsum (5, 7) (5, 8) (7, 7) (7, 8) i (2, 4) (2, (3,4)) (2, (3,5)) (2, 7) (2, (6,7)) (2, (6,8)) (4, 4) (4, (3,4)) (4, (3,5)) (4, 7) (4, (6,7)) (4, (6,8)) (5, 7) (5, (6,7)) (5, (6,8)) (7, 7) (7, (6,7)) (7, (6,8)) defs after use in loop, these are valid DU pairs No def-clear path … different scope for i No path through graph from nodes 5 and 7 to 4 or 3

DU Paths for Stats variable DU Pairs DU Paths numbers (1, 4) (1, 5) (1, 7) [ 1, 2, 3, 4 ] [ 1, 2, 3, 5 ] [ 1, 2, 3, 5, 6, 7 ] length (1, 8) (1, (3,4)) (1, (3,5)) (1, (6,7)) (1, (6,8)) [ 1, 2, 3, 5, 6, 8 ] med (5, 8) [ 5, 6, 8 ] var (8, 8) No path needed sd sum (4, 4) (4, 5) [ 4, 3, 4 ] [ 4, 3, 5 ] variable DU Pairs DU Paths mean (5, 7) (5, 8) [ 5, 6, 7 ] [ 5, 6, 8 ] varsum (7, 7) (7, 8) [ 7, 6, 7 ] [ 7, 6, 8 ] i (2, 4) (2, (3,4)) (2, (3,5)) (4, 4) (4, (3,4)) (4, (3,5)) (5, (6,7)) (5, (6,8)) (7, (6,7)) (7, (6,8)) [ 2, 3, 4 ] [ 2, 3, 5 ] [ 4, 3, 4 ] [ 4, 3, 5 ]

DU Paths for Stats – No Duplicates There are 38 DU paths for Stats, but only 12 unique [ 1, 2, 3, 4 ] [ 1, 2, 3, 5 ] [ 1, 2, 3, 5, 6, 7 ] [ 1, 2, 3, 5, 6, 8 ] [ 2, 3, 4 ] [ 2, 3, 5 ] [ 4, 3, 4 ] [ 4, 3, 5 ] [ 5, 6, 7 ] [ 5, 6, 8 ] [ 7, 6, 7 ] [ 7, 6, 8 ] 2 require at least two iterations of a loop 6 require at least one iteration of a loop 4 expect a loop not to be “entered”

Test Cases and Test Paths Test Case : numbers = (44) ; length = 1 Test Path : [ 1, 2, 3, 4, 3, 5, 6, 7, 6, 8 ] Additional DU Paths covered (no sidetrips) [ 1, 2, 3, 4 ] [ 2, 3, 4 ] [ 4, 3, 5 ] [ 5, 6, 7 ] [ 7, 6, 8 ] The five stars that require at least one iteration of a loop Test Case : numbers = (2, 10, 15) ; length = 3 Test Path : [ 1, 2, 3, 4, 3, 4, 3, 4, 3, 5, 6, 7, 6, 7, 6, 7, 6, 8 ] DU Paths covered (no sidetrips) [ 4, 3, 4 ] [ 7, 6, 7 ] The two stars that require at least two iterations of a loop Other DU paths require arrays with length 0 to skip loops But the method fails with index out of bounds exception… med = numbers [length / 2]; A fault was found

Example: Def-Use Associations read (z) x = 0 y = 0 if (z  0) { x = sqrt (z) if (0  x && x  5) y = f (x) else y = h (z) } y = g (x, y) print (y) def-use associations for variable z.

Example: Def-Use Associations read (z) x = 0 y = 0 if (z  0) { x = sqrt (z) if (0  x && x  5) y = f (x) else y = h (z) } y = g (x, y) print (y) def-use associations for variable x.

Example: Def-Use Associations read (z) x = 0 y = 0 if (z  0) { x = sqrt (z) if (0  x && x  5) y = f (x) else y = h (z) } y=g (x, y) print (y) def-use associations for variable y.

Using Control-flow Testing to Test Function ABS Consider the following function: /* ABS This program function returns the absolute value of the integer passed to the function as a parameter. INPUT: An integer. OUTPUT: The absolute value if the input integer. */ 1                  int ABS(int x) 2                  { 3                  if (x < 0) 4                  x = -x; 5                  return x; 6                  }

Example: Using Control-flow Testing to Test Program COUNT Consider the following program: /* COUNT This program counts the number of characters and lines in a text file. INPUT: Text File OUTPUT: Number of characters and number of lines. */ 1                  main(int argc, char *argv[]) 2                  { 3                  int numChars = 0; 4                  int numLines = 0; 5                  char chr; 6                  FILE *fp = NULL; 7                 

Program COUNT (Cont’d) 8                  if (argc < 2) 9                  { 10              printf(“\nUsage: %s <filename>”, argv[0]); 11              return (-1); 12              } 13              fp = fopen(argv[1], “r”); 14              if (fp == NULL) 15              { 16              perror(argv[1]); /* display error message */ 17              return (-2); 18              }

Program COUNT (Cont’d) 19 while (!feof(fp)) 20              { 21              chr = getc(fp); /* read character */ 22              if (chr == ‘\n’) /* if carriage return */ 23              ++numLines; 24              else 25              ++numChars; 26              } 27              printf(“\nNumber of characters = %d”, numChars); 28              printf(“\nNumber of lines = %d”, numLines); 29              }

An example: All-du-paths What are all the du-paths in the following program ? read (x,y); for (i = 1; i <= 2; i++) print (“hello”); if (y < 0) print (x);

Example: pow(x,y)

Def-Use Pairs (3) /** Euclid's algorithm */ public class GCD { public int gcd(int x, int y) { int tmp; // A: def x, y, tmp while (y != 0) { // B: use y tmp = x % y; // C: def tmp; use x, y x = y; // D: def x; use y y = tmp; // E: def y; use tmp } return x; // F: use x Data flow information is associated with locations in the program, or equivalently, with nodes in the program control flow graph. We mark each location with the sets of variables defined and used at those locations. Note that in node A (beginning of the procedure) x, y, and tmp are defined. x and y receive the values passed to them through parameters, while the declaration of tmp is treated like an assignment of a special value “uninitialized”. Line c (node c in the graph at right) shows how an assignment statement typically defines one thing (tmp, in this case) and uses all the variables that are used in computing that value (x and y, in this case). Line F (node f at right) shows that returning a value from a method or function is also a use of that value. Essentially we are considering that the return value will be used where the function or method is called.

Find all DU for x and y Public int gcd (int x, int y) { int tmp; While (y!= 0) tmp= x % y; x = y; y = tmp; } return x;

Call Graph The most common graph for structural design testing Nodes : Units (in Java – methods) Edges : Calls to units Example call graph A B C D F E Node coverage : call every unit at least once (method coverage) Edge coverage : execute every call at least once (call coverage)

Overestimating the calls relation The static call graph includes calls through dynamic bindings that never occur in execution. public class C { public static C cFactory(String kind) { if (kind == "C") return new C(); if (kind == "S") return new S(); return null; } void foo() { System.out.println("You called the parent's method"); public static void main(String args[]) { (new A()).check(); class S extends C { System.out.println("You called the child's method"); class A { void check() { C myC = C.cFactory("S"); myC.foo(); A.check() C.foo() S.foo() CcFactory(string)

Contex Insensitive Call graphs public class Context { public static void main(String args[]) { Context c = new Context(); c.foo(3); c.bar(17); } void foo(int n) { int[] myArray = new int[ n ]; depends( myArray, 2) ; void bar(int n) { depends( myArray, 16) ; void depends( int[] a, int n ) { a[n] = 42; main C.foo C.bar C.depends

Contex Sensitive Call graphs public class Context { public static void main(String args[]) { Context c = new Context(); c.foo(3); c.bar(17); } void foo(int n) { int[] myArray = new int[ n ]; depends( myArray, 2) ; void bar(int n) { depends( myArray, 16) ; void depends( int[] a, int n ) { a[n] = 42; main C.foo(3) C.bar(17) C.depends(int(3),a,2) C.depends (int(3),a,2)

Context Sensitive CFG exponential growth B D F H C E G I J 1 context A 2 contexts AB AC 4 contexts ABD ABE ACD ACE 8 contexts … 16 calling contexts …

Data Flow at the Design Level Caller : A unit that invokes another unit Callee : The unit that is called Callsite : Statement or node where the call appears Actual parameter : Variable in the caller Formal parameter : Variable in the callee

Example Call Site A  B (x)  end A B (Y)  end B interface Caller interface Actual Parameter Callee Formal Parameter Applying data flow criteria to def-use pairs between units is too expensive Too many possibilities But this is integration testing, and we really only care about the interface …

Inter-procedural DU Pairs If we focus on the interface, then we just need to consider the last definitions of variables before calls and returns and first uses inside units and after calls Last-def : The set of nodes that define a variable x and has a def-clear path from the node through a callsite to a use in the other unit Can be from caller to callee (parameter or shared variable) or from callee to caller as a return value First-use : The set of nodes that have uses of a variable y and for which there is a def-clear and use-clear path from the callsite to the nodes

Example Inter-procedural DU Pairs Caller x = 5 x = 4 x = 3 B (x) 1 2 3 4 F X = 14  y = G (x)  print (y) callsite first-use last-def DU pair 11 B (int y) Z = y T = y print (y) 10 12 13 DU pair Callee G (a) print (a)  b = 42  return (b) Last Defs 2, 3 First Uses 11, 12

Example – Quadratic 25 ok = Root (X, Y, Z); 26 if (ok) 27 System.out.println 28 (“Quadratic: ” + Root1 + Root2); 29 else 30 System.out.println (“No Solution.”); 31 } 32 33 // Three positive integers, finds quadratic root 34 private static boolean Root (int A, int B, int C) 35 { 36 float D; 37 boolean Result; 38 D = (float) Math.pow ((double)B, (double2-4.0)*A*C ); 39 if (D < 0.0) 40 { 41 Result = false; 42 return (Result); 43 } 44 Root1 = (float) ((-B + Math.sqrt(D))/(2.0*A)); 45 Root2 = (float) ((-B – Math.sqrt(D))/(2.0*A)); 46 Result = true; 47 return (Result); 48 } / /End method Root 49 50 } // End class Quadratic 1 // Program to compute the quadratic root for two numbers 2 import java.lang.Math; 3 4 class Quadratic 5 { 6 private static float Root1, Root2; 7 8 public static void main (String[] argv) 9 { 10 int X, Y, Z; 11 boolean ok; 12 int controlFlag = Integer.parseInt (argv[0]); 13 if (controlFlag == 1) 14 { 15 X = Integer.parseInt (argv[1]); 16 Y = Integer.parseInt (argv[2]); 17 Z = Integer.parseInt (argv[3]); 18 } 19 else 20 { 21 X = 10; 22 Y = 9; 23 Z = 12; 24 } © Ammann & Offutt

shared variables last-defs 1 // Program to compute the quadratic root for two numbers 2 import java.lang.Math; 3 4 class Quadratic 5 { 6 private static float Root1, Root2; 7 8 public static void main (String[] argv) 9 { 10 int X, Y, Z; 11 boolean ok; 12 int controlFlag = Integer.parseInt (argv[0]); 13 if (controlFlag == 1) 14 { 15 X = Integer.parseInt (argv[1]); 16 Y = Integer.parseInt (argv[2]); 17 Z = Integer.parseInt (argv[3]); 18 } 19 else 20 { 21 X = 10; 22 Y = 9; 23 Z = 12; 24 } shared variables last-defs

first-use first-use last-def last-defs 25 ok = Root (X, Y, Z); 26 if (ok) 27 System.out.println 28 (“Quadratic: ” + Root1 + Root2); 29 else 30 System.out.println (“No Solution.”); 31 } 32 33 // Three positive integers, finds the quadratic root 34 private static boolean Root (int A, int B, int C) 35 { 36 float D; 37 boolean Result; 38 D = (float) Math.pow ((double)B, (double2-4.0)*A*C); 39 if (D < 0.0) 40 { 41 Result = false; 42 return (Result); 43 } 44 Root1 = (float) ((-B + Math.sqrt(D)) / (2.0*A)); 45 Root2 = (float) ((-B – Math.sqrt(D)) / (2.0*A)); 46 Result = true; 47 return (Result); 48 } / /End method Root 49 50 } // End class Quadratic first-use first-use last-def last-defs

Quadratic – Coupling DU-pairs Pairs of locations: method name, variable name, statement (main (), X, 15) – (Root (), A, 38) (main (), Y, 16) – (Root (), B, 38) (main (), Z, 17) – (Root (), C, 38) (main (), X, 21) – (Root (), A, 38) (main (), Y, 22) – (Root (), B, 38) (main (), Z, 23) – (Root (), C, 38) (Root (), Root1, 44) – (main (), Root1, 28) (Root (), Root2, 45) – (main (), Root2, 28) (Root (), Result, 41) – ( main (), ok, 26 ) (Root (), Result, 46) – ( main (), ok, 26 )

Types of Def-Use Pairs def use A () intra-procedural data flow (within the same unit) inter-procedural data flow def A () B () use last-def A () first-use B () full coupling def A() use B() A() B() F () object-oriented direct coupling data flow object-oriented indirect coupling data flow def A() use B() M () N() F() A() M() B() N()

Example of Control Flow Graph public static String collapseNewlines(String argStr) { char last = argStr.charAt(0); StringBuffer argBuf = new StringBuffer(); for (int cIdx = 0 ; cIdx < argStr.length(); cIdx++) char ch = argStr.charAt(cIdx); if (ch != '\n' || last != '\n') argBuf.append(ch); last = ch; } return argBuf.toString();

File ADT Example class FileADT has three methods: open (String fName) // Opens file with name fName close () // Closes the file and makes it unavailable write (String textLine) // Writes a line of text to the file s1 s2 s3 s4 s5 s6 open (f) write(t) write (t) close () Valid sequencing constraints on FileADT: An open (f) must be executed before every write (t) An open (f) must be executed before every close () A write (f) may not be executed after a close () unless there is an open (f) in between A write (t) should be executed before every close ()

Is there a path that violates any of the sequencing constraints ? Static Checking Is there a path that violates any of the sequencing constraints ? s1 s2 s3 s4 s5 s6 open (f) write(t) write (t) close () Is there a path to a write() that does not go through an open() ? Is there a path to a close() that does not go through an open() ? Is there a path from a close() to a write()? Is there a path from an open() to a close() that does not go through a write() ? (“write-clear” path) [ 1, 3, 4, 6 ] – ADT use anomaly!

Static Checking Consider the following graph : close () s1 s2 s3 s4 s5 s8 open (f) write (t) s6 s7 [ 7, 3, 4 ] – close () before write () !

Inheritance & Polymorphism Caution : Ideas are preliminary and not widely used Example inheritance hierarchy graph A B C D Classes are not executable, so this graph is not directly testable We need objects A B C D a b d c objects What is coverage on this graph ?

Coverage on Inheritance Graph Create an object for each class ? This seems weak because there is no execution Create an object for each class and apply call coverage? OO Call Coverage : TR contains each reachable node in the call graph of an object instantiated for each class in the class hierarchy. OO Object Call Coverage : TR contains each reachable node in the call graph of every object instantiated for each class in the class hierarchy. Data flow is probably more appropriate …

Access Control (in Java) Class 1 Package public members protected members Class 3 default private members inheritance Class 2 Class 5 Class 4 © Ammann and Offutt

Additional Definitions Inheritance : If class B inherits from class A, then all variables and methods in A are implicitly in B, and B can add more A is the parent or ancestor B is the child or descendent An object reference obj that is declared to be of type A can be assigned an object of either type A, B, or any of B’s descendents Declared type : The type used in the declaration: A obj; Actual type : The type used in the object assignment: obj = new B(); Class (State) Variables : The variables declared at the class level, often private

Polymorphism The same variable can have different types depending on the program execution If B inherits from A, then an object of type B can be used when an object of type A is expected If both A and B define the same method M (B overrides A), then the same statement might call either A’s version of M or B’s version

Testing OO Software Intra-method testing : Testing individual methods within classes Inter-method testing : Multiple methods within a class are tested in concert Intra-class testing : Testing a single class, usually using sequences of calls to methods within the class Inter-class testing : More than one class is tested at the same time (integration)

Example DU Pairs and Anomalies Consider what happens when an overriding method has a different def-set than the overridden method B +h () +i () -x A -u -v -w +h() +i() +j() +l() C +j () -y def-use Method Defs Uses A::h () {A::u, A::w} A::i () {A::u} A::j () {A::v} {A::w} A::l() B::h() {B::x} B::i() C::i() C::j() {C::y} A::h() calls j(), B::h() does not DU anomaly DU anomaly def-use

Polymorphism Headaches (Yo-Yo) Actual type A d() g() h() i() j() l() +d () +g () +h () +i () +j () +l () B h() i() k() C i() j() l() Object is of actual type A A::d ()

Polymorphism Headaches (Yo-Yo) g() h() i() j() l() +d () +g () +h () +i () +j () +l () B h() i() k() C i() j() l() A d() g() h() i() j() l() B Actual type +h () +i () +k () B h() i() k() C i() j() l() Object is of actual type B B::d ()

Polymorphism Headaches (Yo-Yo) g() h() i() j() l() +d () +g () +h () +i () +j () +l () B h() i() k() C i() j() l() A d() g() h() i() j() l() B +h () +i () +k () B h() i() k() C i() j() l() A d() g() h() i() j() l() B h() i() k() C Actual type +i () +j () +l () C i() j() l() Object is of actual type C, C::d ()

OO Faults and Anomalies Acronym Fault / Anomaly ITU Inconsistent Type Use SDA State Definition Anomaly SDIH State Definition Inconsistency SDI State Defined Incorrectly IISD Indirect Inconsistent State Definition ACB1 Anomalous Construction Behavior (1) ACB2 Anomalous Construction Behavior (2) IC Incomplete Construction SVA State Visibility Anomaly

Inconsistent Type Use (ITU) No overriding (no polymorphism) C extends T, and C adds new methods (extension) An object is used “as a C”, then as a T, then as a C Methods in T can put object in state that is inconsistent for C s.push (“Steffi”); s.push (“Joyce”); s.push (“Andrew”); dumb (s); s.pop(); void dumb (Vector v) { v.removeElementAt (v.size()-1); } Vector -array +insertElementAt() +removeElementAt() // Stack is empty! Stack +pop (): Object +push (): Object call call

State Definition Anomaly (SDA) X extends W, and X overrides some methods The overriding methods in X fail to define some variables that the overridden methods in W defined W v u m() n() X x Y w W::m () defines v and W::n() uses v X::n () uses v Y::m () does not define v For an object of actual type Y, a data flow anomaly exists and results in a fault if m() is called, then n()

State Definition Inconsistency (SDIH) Hiding a variable, possibly accidentally If the descendant’s version of the variable is defined, the ancestor’s version may not be W v u m() n() X x Y Y overrides W’s version of v Y::m() defines Y::v X::n() uses v … getting W’s version of v For an object of type Y, a data flow inconsistency may exist and result in a fault if m() is called, then n() overrides (hides)

Anomalous Construction Behavior (ACB1) Constructor of W calls a method f() A child of W, X, overrides f() X::f() uses variables that should be defined by X’s constructor W W() f() X x Calls Uses Overrides When an object of type X is constructed, W() is run before X(). When W() calls X::f(), x is used, but has not yet been given a value!

State Visibility Anomaly (SVA) A private variable v is declared in ancestor W, and v is defined by W::m() X extends W and Y extends X Y overrides m(), and calls W::m() to define v W -v m() X Y Overrides, calls W -v m() X Y Overrides, calls Overrides X::m() is added later Y:m() can no longer call W::m()!

Need to consider the set of interactions that can occur: Testing Goals We want to test how a method can interact with instance bound to object o: Interactions occur through the coupling sequences Need to consider the set of interactions that can occur: What types can be bound to o? Which methods can actually execute? (polymorphic call sets) Test all couplings with all type bindings possible

Web Applications and Other Distributed Software use B() P1 def A() message P2 distributed software data flow “message” could be HTTP, RMI, or other mechanism A() and B() could be in the same class or accessing a persistent variable such as in a web session Beyond current technologies