CPSC 333: Condition Testing

Location: [CPSC 333] [Listing by Topic] [Listing by Date] [Previous Topic] [Next Topic] Condition Testing


This material was covered during lectures on March 31, 1997.


Introduction

Condition Testing is another structural testing method that is useful during unit testing, using source code or detailed pseudocode as a reference for test design.

Its goal is the thorough testing of every condition or test that occurs in the source code. While path testing does provide some limited coverage of conditions, by assuring that every outcome (true and false) of every condition is covered by at least one test case, condition testing provides much better coverage for conditions that are ``complex.''

Types of Conditions

The method is easy to describe: It includes a ``checklist'' of cases to be covered for each kind of condition that one might find in source code, in the test for an if-then or if-then-else statement, or as the test for a while-do or repeat-until loop.

Simple Conditions

Boolean Variables

A boolean variable, or (application of a) boolean function, is one kind of simple condition.

Relational Expressions

Relational expressions are comparisons of two values of the same type. If v1 and v2 are values of the same type, and it is possible to test ``equality'' of values of this type, then two (kinds of) relational expressions involving this type are

If the type is ``ordered'' then additional relational expressions are also possible:

In all cases, a truth value (either true or false) is obtained whenever you assign values of the given type to each of the variables v1 and v2. Of course, ``v1'' and ``v2'' might also be (calls to) functions returning values of the given type, in the expressions given above.

Compound Conditions

Compound conditions are conditions that are obtained by combining together simple conditions, using ``logical connectives,'' such as ``and'' ( && ), ``or'' ( || ), or ``not'' ( ! ); additional connectives, such as ``implies'', ``nand,'' or ``exclusive or'' might also be used.

Guidelines for Test Design

As mentioned above, a ``checklist'' or simple rule describing required test cases can be given for each of the kinds of conditions listed above.

Guidelines for Simple Conditions

Guidelines for Boolean Variables

In this case, two test cases should be covered:

Guidelines for Relational Expressions

Suppose the relational expression to be considered is

e1 op e2

where e1 and e2 are expressions of the same type, and op is one of the comparisons (==, !=, <, and so on) listed above.

If this is an ``ordered'' type, so that it makes sense to ask whether e1 is ``less than'' e2, then three cases should be covered by tests:

On the other hand, if the type is not ``ordered,'' then only two cases need to be covered (or, can be distinguished):

Guidelines for Compound Conditions

Note that either two or three cases need to be covered for each one of the simple conditions listed above.

As described above, a compound condition connects some number of simple conditions together, using logical connectives. Suppose that a complex condition connects k simple conditions with three cases, and h simple conditions with two cases, together. Then, it is possible - in principle - to define a total of

3k 2h

different combinations of these cases.

Some might be impossible to achieve. For example, if x, y, and z are variables of the same ordered type, and three of the relational expressions included in the compound condition are

  1. x < y,
  2. y < z,
  3. x < z

then one of the (twenty-seven) combinations of cases that you'd get by considering these three relational expressions would be equivalent to the following condition on x, y, and z:

(x < y) && (y < z) && (x > z)

It should be clear that there is no way to assign values to x, y and z such that the above condition is satisfied.

The guideline for ``compound combinations'' is now easy to state: For each of the above combinations of conditions that is possible, include a test such that this combination of conditions holds at some point (during execution of the program) when the condition is checked.

case or switch Statements

The guidelines given above only mention two-way conditions and, of course, the kinds of conditions included in case or switch statements are a bit different. However, path testing appears to provide adequate testing for these statements, so we won't concern ourselves with these statements any further.

Application to an Example

Once again, consider the sorting program that is being used as an ongoing example for unit testing. Recall that three tests were identified for this program when path testing was applied.

The source code (more accurately, pseudocode) for this program includes two conditions, that appear as the tests for the two while loops that it contains.

First Condition

The test for the outer loop is (or can be written as)

i <= n

This is clearly an example of a relational expression. It involves integers, and integer is an ordered type - so there are three cases that should be covered by tests:

  1. i < n
  2. i == n
  3. i > n

Second Condition

The second condition, which is the test for the inner loop, is a compound condition involving a pair of relational expressions:

(j >= 1) && (A[j] > A[j+1])

Both of the relational expressions involve an ordered type, so that there are 32 = 9 combinations that should be considered:

  1. (j < 1) && (A[j] < A[j+1])
  2. (j < 1) && (A[j] == A[j+1])
  3. (j < 1) && (A[j] > A[j+1])
  4. (j == 1) && (A[j] < A[j+1])
  5. (j == 1) && (A[j] == A[j+1])
  6. (j == 1) && (A[j] > A[j+1])
  7. (j > 1) && (A[j] < A[j+1])
  8. (j > 1) && (A[j] == A[j+1])
  9. (j > 1) && (A[j] > A[j+1])

Cases Covered by Existing Tests

Some - but not all - of the above cases are covered by the tests that were specified for this program using path testing. In particular,

The remaining cases - the first case applying to the first condition, and the fifth, seventh, eighth, and ninth cases applying to the second conditions - aren't covered by any of the test that have been developed so far.

New Tests

Test #4

We'll begin by covering the fifth case that is required for the second condition (because this is the only remaining case that can be covered using a test in which n=2):

Test #4
Inputs: n = 2; A[1] = 1, A[2] = 1
Expected Outputs: A[1] = 1, A[2] = 1

Now, the above case is covered by this test, at the beginning of the first execution of the inner while loop.

Test #5

The first case for the first condition can be covered by any test for which n is greater than or equal to 3; it's always covered at the beginning of the first execution of the outer while loop. Thus, this condition is covered by all three of the remaining tests given below.

The fifth test will also cover the seventh case that applies to the second condition, at the beginning of the first execution of the inner while loop.

Test #5
Inputs: n=3; A[1] = 1, A[2] = 2, A[3] = 3
Expected Outputs: A[1] = 1, A[2] = 2, A[3] = 3

Test #6

The sixth test will cover the eighth case that applies to the second condition, at the beginning of the first execution of the inner while loop.

Test #6
Inputs: n=3; A[1] = 1, A[2] = 2, A[3] = 2
Expected Outputs: A[1] = 1, A[2] = 2, A[3] = 2

Test #7

The seventh test will cover the remaining ninth case that applies to the second condition - also at the beginning of the first execution of the inner while loop.

Test #7
Inputs: n = 4; A[1] = 1, A[2] = 3, A[3] = 2
Expected Outputs: A[1] = 1, A[2] = 2, A[3] = 3

Lab Exercise

A lab exercise based on this material is also available.

Location: [CPSC 333] [Listing by Topic] [Listing by Date] [Previous Topic] [Next Topic] Condition Testing


Department of Computer Science
University of Calgary

Office: (403) 220-5073
Fax: (403) 284-4707

eberly@cpsc.ucalgary.ca