White-Box Testing

White-Box Testing

  • Technique to ensure code works as expected
  • Exercise all paths in the code
  • Equivalence partitioning and boundary value analysis
  • Provides measures of how thoroughly the test cases exercise the code

White-Box Testing

  • Takes into account the internal mechanism of a system or component.

 

  • Also known as structural testingclear box testingglass box testing.

Types of Testing

  • Unit Testing - a unit is a software component that cannot be subdivided into other components.

 

  • Integration Testing - software components, hardware components or both are combined and tested to evaluate the interaction between them.

 

  • Regression Testing - selective retesting of a system or component to verify that modifications have not caused unintended effects and that the system or component still complies with its specified requirements.

Stubs and Drivers

public class StringToInteger {

	public static void main(String[] args) {
		// Driver
		System.out.println(stringToInteger("234"));
		System.out.println(stringToInteger("-234"));
		System.out.println(stringToInteger2("234"));
		System.out.println(stringToInteger2("-234"));
	}
	
	private static int stringToInteger(String numberString){
		// Stub - to be filled in to form the actual method
	}
}

Stubs and Drivers

public class StringToInteger {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		System.out.println(stringToInteger("234"));
		System.out.println(stringToInteger("-234"));
		System.out.println(stringToInteger2("234"));
		System.out.println(stringToInteger2("-234"));
	}
	
	private static int stringToInteger(String numberString){
	        /**
		 * Uses horner's rule 
		 * Multiplies each successive digit by 10 and adds it to the value of the previous digit
		 */
		char[] strArray = numberString.toCharArray();
		int integerValue = 0;
		int charValue;
		boolean isNegative = false;
		int start = 0;
		if (strArray[0] == '-'){
			isNegative = true;
			start = 1;
		}
		
		while (start < strArray.length){
			//beware of infinite loops - always increment your counter
			charValue = strArray[start] - '0';
			integerValue = integerValue * 10 + charValue;
			start = start + 1;
		}
		
		if (isNegative){
			integerValue = -integerValue;
		}
		return integerValue;	
	}
}

Deriving Test Cases

  • Basis Path Testing
  • Equivalence Partitioning/Boundary Value Analysis
  • Control Flow/Coverage Testing
  • Data Flow Testing
  • Failure ("Dirty") Test Cases

These methods will serve as guidelines for you as you design test cases.

Basis Path Testing

  • Ensures that all independent paths through a code module have been tested.

 

  • Independent Path is any path through the code that introduces at least one new set of processing statements or a new condition.

 

  • Provides a minimum lower bound on the number of test cases that need to be written.

Basis Path Testing (2)

  • Main objective is to identify the number of decision points in the module. A flow graph helps.

 

If a player lands on a property owned by other players, he or she needs to pay the rent. If the player does not have enough money, he or she is out of the game. If the property is not owned by any players and the player has enough money buying the property, he or she may buy the property with the price associated with the property.

Logical conditions include if-thenif-then-elseselection, or loops.

Using this flow graph, we can compute the number of independent paths through the code.

Count the number of conditionals/predicates and add 1. Six independent paths through the code

We need to write a test case to ensure that each of these paths is tested at least once. This is the lower bound.

Equivalence Partitioning/Boundary Value Analysis

  • Whenever you encounter any kind of number or limit in a requirement, you should be alert for EP/BVA issues.
  • In our example, we would want to ensure our test cases include the following:

 

Equivalence Partitioning/Boundary Value Analysis

  • With programming loops (such as while loops), consider EP and execute loops in the middle of their operational bound.

 

  • For Boundary Value Analysis, you want to ensure that you execute loops right belowright at, and right above their boundary conditions.

 

Control Flow/Coverage Testing

  • We generally write methods to ensure they are testable by having the method return a value.
  • We also predetermine the "answer" that is returned when the method is called with certain parameters.
  • Use the simplest set of input that could possibly test your situation.
  • Adequacy of test cases is often measured with a metric called coverage.
  • So what are we "covering"?

Method Coverage

  • A measure of the percentage of methods that have been executed by test cases.
  • Does it make sense to deliver a product with methods that were never tested?
  • Your tests should call 100% of your methods. 

Method Coverage

  • A measure of the percentage of methods that have been executed by test cases.
  • Does it make sense to deliver a product with methods that were never tested?
  • Your tests should call 100% of your methods. 

Method Coverage

class AmazingGrace {
    public int howSweetIsTheSound(String sound){
        // calculate how sweet the sound is
        return 1;
    }

    public boolean savedAWretch(Person person){
        // Did amazing grace save this wretch
        return true;
    }
}
class AmazingGraceTest {
    @Test
    public void testHowSweetIsTheSound(){
        String sound = "xasxasdsaxs";
        AmazingGrace amazingGrace = new AmazingGrace();
        assertEquals(amazingGrace.howSweetIsTheSound(sound), 1);  
    } 

    @Test
    public void testSavedaWretch(){
        Person person = new Person();
        AmazingGrace amazingGrace = new AmazingGrace();
        assertEquals(amazingGrace.savedAWretch(person), true);
    }
}

100% method coverage since all methods are tested by the test cases.

Statement Coverage

  • Statement coverage is the measure of the percentage of statements that have been executed by test cases.
  • Your objective should be to achieve 100% statement coverage through your testing.
  • Identifying the independent paths and executing the minimum n umber of test cases will make this statement coverage achievable.

Statement Coverage

int foo(int a, int b, int c, int d, float e){
    float e;
    if (a == 0){
        return 0;
    }
    int x = 0;
    if ((a == b) OR ((c == d) AND goNuclear(a)){
        x = 1;
    }
    e = 1/x;
    return e;
}

Test case 1: foo(0, 0, 0, 0, 0)

Test case 2: foo(1, 1, 1, 1, 1)

100% statement coverage required two test cases

Branch Coverage

  • Branch coverage is a measure of the percentage of the decision points (Boolean expressions) of the program that have been evaluated as both true and false in test cases.

Branch Coverage

int foo(int a, int b, int c, int d, float e){
    float e;
    if (a == 0){ // DECISION POINT 1
        return 0;
    }
    int x = 0;
    if ((a == b) OR ((c == d) AND goNuclear(a)){ // DECISION POINT 2
        x = 1;
    }
    e = 1/x;
    return e;
}

For decision/branch coverage, we evaluate an entire Boolean expression as one true-or-false predicate.

Condition Coverage

  • A measure of percentage of Boolean sub-expressions of the program that have been evaluated as both true or false outcomes in test cases.

Condition Coverage

int foo(int a, int b, int c, int d, float e){
    float e;
    if (a == 0){ // DECISION POINT 1
        return 0;
    }
    int x = 0;
    if ((a == b) OR ((c == d) AND goNuclear(a)){ 
        // three subexpresions
        // goNuclear returns FALSE if passed a value greater than 1
        x = 1;
    }
    e = 1/x;
    return e;
}

Failure ("Dirty") Test Cases

  • Look at the structure of your code and think about every possible way a user might break it.
  • Suggestions
    • Look at every input into the code you are testing. Do you handle each input if it is incorrect, the wrong data type?
    • Can a user overflow a buffer, causing a security problem?
    • Look at every calculation. Could it possibly create an overflow? Have you protected every possible division by zero?
Made with Slides.com