Department of Engineering

IT Services

Testing code: the basics

"Testing reveals the presence, but not the absence of bugs" - Dijkstra

The best time to think about how to test your code is before you write it. This page describes some commonly used procedures which become more useful the bigger your program gets

Equivalence partitioning

When testing a function it's often infeasible to try all possible inputs. Instead, try to identify sets of numbers that are likely to behave similarly, and pick a representative value from each set. With sqrt for example, the sets might be -1, 1, 0, other positive numbers and other negative numbers, so -999, -1, 0, 1, 999 might be worth trying.

Unit testing: stubs and drivers

If you're involved in writing a big program but have only finished part of it, how can you test? You can replace unwritten subroutines by stubs (routines that have the same interface as the finished product but do very little), and replace unwritten calling routines by drivers (programs that call the subroutine you've written but do little else).

Assertions

There will be places in the code where the programmer is sure that something should be true. Such beliefs can be checked in C and C++ by using assertions. Here's a silly example.

#include <cassert> int main() { int i=7; assert(i==6); }

If you compile this code and run it you'll get something like

a.out: foo3.cc:7: int main(): Assertion `i==6' failed. Aborted

The useful thing about assertions is that they're easily disabled by using -DNDEBUG on the compile line.

Analysers

Some programs exist to help analyse your code. Even if you don't have them it's worth knowing what they check.

Complexity Analysis tools check how complicated your code is - length of functions, number of returns per function, number of decision points, lengths of loops etc. All these are factors which might increase the chance of errors.

Coverage Analysis tools check whether all functions are called, whether all lines can be reached, etc. This is useful if you're writing a test suite - unless you're calling all the functions, the test suite's incomplete. There may be good reasons why the test suite doesn't cause every line to be exercised, but one should aim to visit as many as possible.

Some compilers can offer help if you ask for it. Using

   g++ -Wall ...

will tell you about C++ code which isn't illegal but might be suspicious (unused variables and functions, etc).

Boundary conditions

Mistakes commonly happen at "boundary conditions" - starts and ends. When checking your code, look at where lists are first added to, where a summation function is called for the first time or the last time, how the first and last elements of arrays are used, etc.

See also