|
|
|
|
|
|
|
One invoice line has been printed for each loop iteration AND
The number of lines output is 1 less than the number of data sets input. |
|
|
|
|
|
|
|
|
The invariant for the outer loop of the Invoice program is then the logical AND of all these assertions. |
|
|
|
|
|
|
|
|
Even if a loop has been properly designed and verified, it is still important to test it rigorously, because there is always the chance of an error creeping in during the implementation phase. Because loops allow us to input many data sets in one run, and because there is the potential for each iteration to be affected by preceding ones, the test data for a looping program is usually more extensive than for a program with just sequential or branching statements. To test a loop thoroughly, we have to check for the proper execution of both a single iteration and multiple iterations. |
|
|
|
|
|
|
|
|
Remember that a loop has seven parts (corresponding to the seven questions in our checklist). A test strategy must test each part. Although all seven parts aren't implemented separately in every loop, the checklist reminds us that some loop operations may serve multiple purposes, each of which should be tested. For example, the incrementing statement in a count-controlled loop may be updating both the process and the ending condition. So it's important to verify that it performs both actions properly with respect to the rest of the loop. |
|
|
|
|
|
|
|
|
The loop invariant is a good place to start in designing test data. The invariant tells us what the acceptable ranges of variables are and what sorts of I/O operations we should see. To test a loop, we try to devise data sets that could cause the variables to go out of range or leave the files in improper states that violate either the loop postcondition or the postcondition of the module containing the loop. |
|
|
|
|
|
|
|
|
In addition to tests based on the invariant, it's good practice to test a loop for four special cases: (1) when the loop is skipped entirely, (2) when the loop body is executed just once, (3) when the loop executes some normal number of times, and (4) when the loop fails to exit. |
|
|
|
|
|
|
|
|
Statements following a loop often depend on its processing. If a loop can be skipped, those statements may not execute correctly. If it's possible to execute a single iteration of a loop, the results can show whether the body performs correctly in the absence of the effects of previous iterations, which can be very helpful when you're trying to isolate the source of an error. Obviously, it's important to test a loop under normal conditions, with a wide variety of inputs. If possible, you should test the loop with real data in addition to mock data sets. Count-controlled loops should be tested to be sure they execute exactly the right number of times. And finally, if there is any chance that a loop might never exit, your test data should try to make that happen. |
|
|
|
|
|