The Art of Software Testing

Chapter 4: Test-Case Design


Glen Myers
Wiley
Third Edition, 2012





  • The most important consideration in program testing is the design and creation of effective test cases

  • Test case design is important because complete testing is impossible

  • Given constraints on time and cost, the key issue of testing becomes:
    What subset of all possible test cases has the highest probability of detecting the most errors?

  • Least effective methodology of all is random-input testing

  • We have to develop a set of thought processes that enable us to select test data more intelligently

  • Chapter 2 tells us that exhaustive Black Box and White Box testing are, in general, impossible

  • You can develop a reasonably-rigorous process by...
    developing test cases for Black Box testing based on requirements and
    examining the logic of the program to develop test cases for White Box testing

  • Recommend that you use a combination of most, if not all, of the test-case design methods to design a rigorous test of a program, since each method has distinct strengths and weaknesses

    Black Box Testing

  • Black Box Testing is based on program requirements

  • Goal is to find areas where the program does not behave according to its requirements

    Equivalence Partitioning

  • Partition the input domain of a program into a finite number of equivalence classes such that you can reasonably assume that a test of a representative value of each class is equivalent to a test of any other value

  • Each test case should invoke as many different input considerations as possible to minimize the total number of test cases necessary

    Input 1 - Equivalence classes 1, 2, 3
    Input 2 - Equivalence classes 4, 5, 6, 7
    Input 3 - Equivalence classes 8, 9

    Test case number -- Input 1 / Input 2 / Input 3

    Test case 1 -- 1 / 4 / 8
    Test case 2 -- 2 / 5 / 9
    Test case 3 -- 3 / 6 / 8
    Test case 4 -- 2 / 7 / 9

  • Avoid using 3 x 4 x 2 = 24 test cases

  • Test case design by Equivalence Partitioning proceeds in two steps:
    (1) Identify the equivalence classes
    (2) Define the test cases

    Identify the Equivalence Classes

  • The Equivalence Classes are identified by taking each input condition (usually a sentence or phrase in the specification) and partitioning it into two or more groups

  • Valid Equivalence Classes represent valid inputs to the program

  • Invalid Equivalence Classes represent all other possible inputs

  • If an input condition specifies a range of values, identify one valid equivalence class in that range and two invalid equivalence classes on either side of it

    value must be between 10 and 20
    valid (10-20)
    invalid (less than 10)
    invalid (greater than 20)

  • If an input condition specifies a "must-be" situation, such as "first character of the value must be a letter," identify one valid equivalence class (it is a letter) and one invalid equivalence class (it is not a letter)

  • If there is any reason to believe that the program does not handle elements in an equivalence class identically, split the equivalence class into multiple equivalence classes

    Define the Test Cases

    1. Assign a unique number to each equivalence class

    2. Until all valid equivalence classes have been covered by (incorporated into) test cases, write a new test case covering as many of the uncovered valid equivalence classes as possible

    Input 1 - Equivalence classes 1, 2, 3
    Input 2 - Equivalence classes 4, 5, 6, 7
    Input 3 - Equivalence classes 8, 9

    Test case number -- Input 1 / Input 2 / Input 3

    Test case 1 -- 1 / 4 / 8
    Test case 2 -- 2 / 5 / 9
    Test case 3 -- 3 / 6 / 8
    Test case 4 -- 2 / 7 / 9

    3. Until your test cases have covered all invalid equivalence classes, write a test case that covers one, and only one, of the uncovered invalid equivalence classes

    Test case 104 -- 35 (invalid) / 7 / 9
    don't use...
    Test case 104 -- 35 (invalid) / 7 / 46 (invalid)

  • The reason that individual test cases should include only one invalid case is that certain erroneous input checks mask or supersede other erroneous input checks

    Boundary Value Analysis

  • Test cases that explore boundary conditions have a higher payoff than test cases that do not

  • Boundary conditions are those situations directly on, above, and beneath the edges of input equivalence classes and output equivalence classes

    value must be between 10 and 20
    valid (be sure to use both 10 and 20)
    valid (probably good to use 11 and 19)
    invalid (be sure to use both 9 and 21)

  • Rather than just focusing attention on the input conditions (input space), test cases are also derived by considering the result space (output equivalence classes)

    1. If an input condition specifies a range of values, write test cases for the ends of the range, and invalid-input test cases for situations just beyond the ends

    2. If an input condition specifies a number of values, write test cases for the minimum and maximum number of values and one beneath and beyond these values

    Use guidelines 1 and 2 for output conditions as well

  • Boundary value analysis, if practiced correctly, is one of the most useful test-case design methods

  • However, it often is used ineffectively because the technique, on the surface, sounds simple

  • Boundary conditions may be very subtle and, hence, identification of them requires a lot of thought

    Error Guessing

  • It has often been noted that some people seem to be naturally adept at program testing

  • Without using any particular methodology such as boundary value analysis, these people seem to have a knack for sniffing out errors

  • One explanation for this is that these people are practicing -- subconsciously more often than not -- a test-case design technique that could be termed Error Guessing

  • Given a particular program, they surmise -- both by intuition and experience -- certain probable types of errors and then write test cases to expose those errors

  • It is difficult to give a procedure for the Error Guessing technique since it is largely an intuitive and ad hoc process

  • The basic idea is to enumerate a list of possible errors or error-prone situations and then write test cases based on the list

  • The presence of the value 0 in a program's input is an error-prone situation
    Therefore, you might write test cases for which particular input values have a 0 value and for which particular output values are forced to 0

  • Where a variable number of inputs or outputs can be present (e.g., the number of entries in a list to be searched), the cases of "none" and "one" (e.g. , empty list, list containing just one entry) are error-prone situations

  • Another idea is to identify test cases associated with assumptions that the programmer might have made when reading the specification (i.e., factors that were omitted from the specification, either by accident or because the writer felt them to be obvious)

    If the specification does not say "A student ID must be a 10-digit number", the software engineer might not check that it is exactly 10 digits or even that it is a number!

    White Box Testing

  • White Box testing is concerned with the degree to which test cases exercise or cover the logic of the source code of the program

  • Ultimate white box test is the execution of every path in the program
    But, complete path testing is not a realistic goal for a program with loops

  • Statement Coverage criterion (execute every statement at least once) is so weak that it generally is useless

  • Decision Coverage (write enough test cases that exercise each possible outcome of all decisions at least once) usually satisfies Statement Coverage

  • Decision Coverage is a stronger criterion than Statement Coverage, but it still is rather weak

  • A criterion that is stronger than Decision Coverage is Multiple Condition Coverage

  • Multiple Condition Coverage -- Write enough test cases to ensure that each condition in a decision takes on all possible outcomes at least once

  • Multiple Condition Coverage is superior to Decision Coverage in that it causes every individual condition in a decision to be executed with both outcomes, whereas Decision Coverage does not

    if (x AND y)

    Decision Coverage -- x FALSE leads to FALSE no matter whether y is TRUE or FALSE

    Multiple Condition Coverage -- requires four test cases
    (x TRUE, y TRUE), (x FALSE, y TRUE),
    (x TRUE, y FALSE), (x FALSE, y FALSE)

  • A set of test cases satisfying the Multiple Condition Coverage criterion also satisfies the Decision Coverage and Statement Coverage

  • For White Box Testing use Multiple Condition Coverage

    The Strategy

  • The test-case design methodologies discussed in this chapter can be combined into an overall strategy

  • The reason for combining them should be obvious
    Each contributes a particular set of useful test cases, but none of them by itself contributes a thorough set of test cases

  • The use of this strategy will not guarantee that all errors will be found, but it has been found to represent a reasonable compromise

  • Also, it represents a considerable amount of hard work

  • Developers willing to go beyond cursory testing, who will dedicate sufficient time to test case design, analyze carefully the test results, and act decisively on the findings, will be rewarded with functional, reliable software that is reasonably error free