05 Testing
05 Testing
Validation
Testing is an example of a more general process called validation. The purpose of
validation is to uncover problems in a program.
Validation includes:
The system may seem to work fine across a broad range of inputs, and then
abruptly fail at a single boundary point. The famous Pentium division bug affected
approximately 1 in 9 billion divisions
Test first programming
In test-first-programming, you write tests before you even write any code. The
development of a single function proceeds in this order:
It gives the types of the parameters and any additional constraints on them (e.g.
sqrt ’s parameter must be nonnegative).
It also gives the type of the return value and how the return value relates to the
inputs
Choosing Test Cases by Partitioning
We divide the input space into subdomains, each consisting of a set of inputs.
The idea behind subdomains is to partition the input space into sets of similar
inputs on which the program has similar behavior. Then we use one representative
of each set.
Example: BigInteger multiplication
/**
*/
BigInteger a = ...;
BigInteger b = ...;
BigInteger ab = a.multiply(b);
Partitioning the input
1. 0
2. 1
3. -1
4. small positive integer
5. small negative integer
6. huge positive integer
7. huge negative integer
Test partitions
Testing boundary values
Bugs often occur at boundaries between subdomains.
Programmers often make off-by-one mistakes (like writing <= instead of <, or
initializing a counter to 0 instead of 1).
Example: boundary values
Let’s consider the function: max : int × int → int
● a<b
● a=b
● a>b
Max function partitions
● a=0 ● b=0
● a<0 ● b<0
● a>0 ● b>0
● a = minimum integer ● b = minimum integer
● a = maximum integer ● b = maximum integer
Test classes for max
1. (1, 2) covers a < b, a > 0, b > 0
2. (-1, -3) covers a > b, a < 0, b < 0
3. (0, 0) covers a = b, a = 0, b = 0
4. (Integer.MIN_VALUE, Integer.MAX_VALUE) covers a < b, a = minint, b =
maxint
5. (Integer.MAX_VALUE, Integer.MIN_VALUE) covers a > b, a = maxint, b =
minint
Two Extremes for Covering the Partition
After partitioning the input space, we can choose how exhaustive we want the test
suite to be:
Cover each part: Every part of each dimension is covered by at least one test
case, but not necessarily every combination.
.
Blackbox and Whitebox Testing
Blackbox testing means choosing test cases only from the specification, not the
implementation of the function.
Whitebox testing (also called glass box testing) means choosing test cases with
knowledge of how the function is actually implemented. e.g., if the implementation
selects different algorithms depending on the input, then you should partition
according to those domains.
Coverage
One way to judge a test suite is to ask how thoroughly it exercises the program.
This notion is called coverage. There are three common kinds of coverage:
A test that tests an individual module, in isolation if possible, is called a unit test.
Testing modules in isolation leads to much easier debugging.
}
Stub (mock) code
Isolating a higher-level module like makeIndex() is possible if we write stub
versions of the modules that it calls.
For example, a stub for getWebPage() wouldn't access the internet at all, but
instead would return mock web page content no matter what URL was passed to
it.
A good testing framework, like JUnit, helps you build automated test suites.
Regression testing
Once you have test automation, it's very important to rerun your tests when you
modify your code.
This prevents your program from regressing — introducing other bugs when you
fix new bugs or add new features.
Running all your tests after every change is called regression testing.
Automated regression testing
In practice, these two ideas, automated testing and regression testing, are used in
combination.
Regression testing is only practical if the tests can be run often, automatically.
Conversely, if you already have automated testing in place for your project, then
you might as well use it to prevent regressions.
Summary
Test-first programming. Write tests before you write code.
White box testing and statement coverage for filling out a test suite.