CPSC 333 --- Lecture 23 --- Monday, March 11, 1996 Loop Testing: Goal: To test while-do, repeat-until, and any other loops in the program thorough --- by trying to ensure that each is executed at minimal, typical, and (if it exists) maximal values --- and to try to "break" the program, by trying to have a loop a fewer-than-minimum as well as a larger-than-maximum number of times. Three types (more accurately, combinations) of loops will be tested: Simple Loops: The loop bodies contain no iterative constructs (so, these are the "innermost" loops if any loops are nested). Nested Loop: One loop is inside the "loop body" of another. Concatenated Loops: One loop follows another "sequentially." Guidelines for Testing Simple Loops: 1. Try to design a test in which the loop body isn't executed at all. 2. Try to design a test in which the loop body is executed exactly once. 3. Try to design a test in which the loop body is executed exactly\ twice. 4. Design a test in which a loop body is executed some "typical" number of times If there is an *upper bound* on the number of times the loop body can be executed (call this n): 5. Design a test in which the loop body is executed n-1 times. 6. Design a test in which the loop body is executed n times. 7. Try to design a test causing the loop body to be executed n+1 times. Guidelines for Testing Nested Loops: 1. Conduct "simple loop tests" for the innermost loop, as described above, while holding the number of iterations of outer loops at minimal nonzero values. 2. Work outward, conducting tests (as described above) for each loop, holding the number of iterations of outer loops at minimal values and holding the number of iterations of inner loops at "typical" values. Guidelines for Testing Concatenated Loops: If the loops are "independent" --- that is, the number of iterations of one loop doesn't depend on the number of iterations of another --- then conduct "simple loop tests" for each one of the loops in the sequence. However, if the loops are "dependent," then use a method similar to the one described above for nested loops: 1. Conduct "simple loop tests" for the *bottom* (or "last") loop, as described above, while holding the number of iterations of higher (or "previous") loops at minimal possible values. 2. Work up, conducting simple loop tests on each loop as you go, holding the number of iterations of lower loops at minimal values and holding the number of iterations of upper loops at minimal values. Applying the Guidelines to the Example Program (from the Wednesday, March 6 Lecture): The example program contains two nested while loops. For this example, the maximum possible number of iterations of the inner loop (on any execution of that loop) must be less than or equal to the number of iterations of the outer loop --- so a "minimal" number of iterations of the outer loop would be the number of iterations of the inner loop the last time the inner loop is executed. To cause the number of iterations of the inner loop (on one run) to be as large as the number of iterations of the outer loop, for *this* program, you would provide an input array such that the smallest element of the array is at the end of the input, so that it's necessary to "bubble" that element all the way to the front of the input array in order to sort the array. Let's "pretend" that the program isn't supposed to be applied to arrays of length more than 100 --- so that the "maximum number" of iterations of the outer loop is 99. Then, when applying the above guidelines to design tests, you'd - start with the inner while loop, which controls the "bubbling forward" of a single element of the array. To design a test in which the inner loop is never executed at all, you'd provide an input array that's already sorted. To design a test in which the inner loop is executed once on a run, you could provide an input in which the array is "almost" sorted: To do this while keeping the number of iterations of the *outer* loop small, you could use an input array of size 2 in which the elements aren't sorted in increasing order. To design a test in which the inner loop is executed *k* times (for any positive integer k you want) while keeping the number of iterations of the outer loop as small as possible, you could provide an input array of length k+1 such that the first k elements are sorted and such that the k+1 st element is the smallest of the inputs. Given the above assumption you might decide tests as described above, for k=2, 50, 98, 99 --- and 100 (that is, providing an input of size 101, when you "know" that the program is only supposed to deal with inputs of size 100). - moving to the outer loop: You'd apply the guidelines given above. To ensure that the outer loop is executed k times, it's sufficient to provide an input array (*any* input array will do) ... of size k_1.