Specification
-
Implementation
float sqrt( float x ) {
require( x >= 0 );
const float eps = 0.0001;
float guess = 1;
while( abs(x - guess * guess ) ) > eps )
guess = ( guess + x / guess ) / 2;
promise( guess * guess - x <= eps );
return guess;
}
slide: Specification and implementation
For example, when testing the function sqrt as specified
in slide [4-sqrt],
a distinction may be made between input arguments
greater than zero, precisely zero, and less than zero.
This results in three cases that must be tested.
For example, input values -2, 0 and 4 may be chosen.
It could be argued, however, that the value 1
should be treated
as another extremum, since sqrt behaves as the identity
on 1.
As another example, imagine that we wish to test a function that sorts
an array of integers, of maximal length say 1000.
First, we need to select a number of different lengths,
say 0, 1, 23 and 1000.
For the latter two cases, we have the choice of filling
the array with random-valued numbers,
numbers in increasing order or numbers in decreasing order.
For each of these distinct possibilities we need to
select a number of test cases.
The assumption underlying the use of equivalence classes
is that one representative of a class is as good as any other.
However, this works only when the assumptions on which our partition
is based are sound.
Moreover, our confidence will probably be stronger the more tests
that are actually carried out.
White-box testing usually involves the notion of a
computation graph, relating the different
parts of the program by means of a flow-diagram.
For white-box testing, criteria are used
such as instruction coverage
(showing that the test set executes each
instruction at least once),
branch coverage
(showing that each possible branch in the program
is taken at least once),
or condition coverage
(showing that the test set causes each
condition to be true and false at least once).
The test cycle
Testing, as so many other things in software development,
is usually an iterative process.
A complete test cycle may be characterized as
consisting of testing the functionality of each
module, integration testing (to check whether the
combination of modules has the desired effect),
testing the system as a whole,
and acceptance testing (in order to get user approval).
See slide [4-cycle].
Test cycle
- module testing
- integration testing
- functional testing
- system testing
- acceptance testing
System testing
- facilities, volume, stress, usability, security, performance
slide: The test cycle
System testing involves checking whether the
system provides all the facilities required by the user
and whether the user interface is satisfactory.
Other aspects that may be of importance are
the extent to which a system can cope with large
volumes of data, whether it performs well on
a heavily loaded network, whether it provides
a sufficient level of security and whether the
performance of the system is adequate in ordinary
circumstances.
For object-oriented software, the criteria of testing
as well as the procedures of testing will virtually
be the same.
However, with respect to component testing
(and to some extent, integration testing and functionality
testing), we may expect significant differences.