Structural Testing
Structural Testing
Types of Testing
When we write unit tests we consider:
• These are two different kinds of test: where we consider details of the
implementation (as in 2 and 3) – known as white box testing – and where
we work from external descriptions, treating the implementation as an opaque
artefact with inputs and outputs: black box testing (as in 1).
• We also distinguish between tests which involve executing the code (dynamic
tests, which we have mainly been looking at) and those which do not: static
tests (code review, for example).
2
Common Errors
• Can be from a particular programming community.
• Professional good practice should make you sensitive to the errors you make
personally.
• The following are the “top three” from David Reilly’s top ten Java programming
errors
– Concurrent access to shared variables by threads (3)
– Capitalization errors (2)
– Null pointers (1)
1/2 3
Capitalization Errors
Remember:
• All methods and member variables in the Java API begin with lowercase letters.
• All methods and member variables use capitalization where a new word begins
— e.g. getDoubleValue().
6
Null pointers
public static void main(String args[]) {
String[] list = new String[3]; // Accept up to 3 parameters
int index = 0;
Structural Testing
• Testing that is based on the structure of the program.
• Usually better for finding defects than for exploring the behaviour of the
system.
• Fundamental idea is that of basic block and flow graph – most work is
defined in those terms.
Two main approaches:
– Control oriented: how much of the control aspect of the code has been
explored?
– Data oriented: how much of the definition/use relationship between data
elements has been explored.
8
Basic Blocks
• A basic block has at most one entry point and usually at most two exit points.
Can you think of exceptions to this?
• We decompose our program into basic blocks. These are the nodes of the
control graph.
• The edges of the control graph indicate control flow — possibly under some
conditions.
9
Statement Testing
• Statement Adequacy: all statements have been executed by at least one
test.
• Statement Coverage: for a particular test T, this is the quotient of the
number of statements executed during a run of T (not counting repeats) and
the number of statements in the program.
• The test set T is adequate if the Statement Coverage is 1.
• For our sample tests: T0 omits ok = 1 at line 34, T1 executes all the code as
does T2.
• In general we do not know if statement coverage is achievable – why?
• All of this can be rephrased in terms of basic blocks – and we look at node
coverage in the control-flow graph.
• Statement coverage is a basic measure but is a fairly poor test of how well we
have exercised the code.
Example 12
Statement Coverage
13
Branch Coverage
• Statement Coverage gives fairly poor coverage of the flow of control in systems.
• For example, we can only guarantee to consider arriving at some basic block
from one of its predecessors.
• Branch adequacy attempts to resolve that:
Let T be a test suite for a program P. T satisfies the branch adequacy criterion
if for each branch B of P there exists at least one test case that exercises B.
• The branch coverage for a test suite is the ratio of branches tested by the
suite and the number of branches in the program under test.
• As usual it is undecidable whether there exists a test suite satisfying the branch
adequacy criterion.
Example 14
Branch Coverage
15
Condition Coverage
• There are issues concerning the adequacy of branch coverage in environments
where we allow compound conditions (because we might take a particular
branch for different reasons).
• This is exacerbated when we have ‘shortcut conditions’ that do not evaluate
some of the condition code.
• We frame this in terms of ‘basic conditions’ i.e. comparisons, basic properties
etc.
• The basic condition adequacy criterion is:
Let T be a test suite for program P. T covers all the basic conditions of P iff
each basic condition of P evaluates to true under some test in T and evaluates
to false under some test in T.
• Possible to extend to a ‘compound’ condition adequacy where all boolean
subformulae in conditions evaluate to both true and false.
Example 16
Condition Coverage
17
Path Coverage
• Condition coverage still gives us a poor coverage of historical executions of the
system.
• Path coverage is better:
Let T be a test suite for program P. T satisfies the path adequacy criterion for
P iff for each path p of P there exists at least one testcase in T that causes
the execution of p.
• Infeasible for all but trivial programs.
• Coverage notion is the ratio of covered paths to total number of paths – tends
to zero for programs with unbounded loops. Why?
• Approach is to consider ‘unrolling’ the code finitely Loop boundary coverage,
each loop is executed: Zero times, Once, More than once
Example 19
Path Coverage
Summary 20
Subsumption Relations