UNIT – V:
State, State Graphs and Transition Testing: State Graphs, Good & Bad State Graphs,
State Testing, and Testability Tips.
Graph Matrices and Application:-Motivational overview, matrix of graph, relations,
power of a matrix, node reduction algorithm.
State, State Graphs and Transition Testing: State Graphs, Good & Bad State Graphs,
State Testing, and Testability Tips.
State graphs, good & bad state graphs
State Graphs by nature are abstract models of behavior of the system. As such, while building
state graph, we need to select relevant states, inputs, and transitions and thereby ignore
irrelevant ones. In the software test design context, we need to deal with good as well as bad
state graphs.
In order to judge whether state graph is good one, we can use following principles:
1. The total number of states in a given state graph is equal to product of the possibilities of
factors that make up the state.
2. For every state and input, there is a unique transition to exactly one state and may be the
same state itself
3. For every transition there is one specific output action.
4. For every state there is a sequence of inputs that will drive the system back to the same
state
Bad state graphs can exhibit certain properties like the following:
1. No exit node which does not allow leaving the state graph. This situation violates the
principle of requirement of at least one exit point. This is as depicted in the following
Figure.
Bugs in State Graphs
When testing an implementation against a State Graph, one shall study the following typical
bugs (incorrect sequences of events, transitions, or actions):
Unspecified transition (nothing happens with an event)
Incorrect transition (the resultant state is incorrect)
Unspecified or incorrect event
Unspecified or incorrect action (wrong things happen as a result of a transition)
Extra, unspecified or corrupt state
Unreachable State (A state that no input sequence can reach
Dead State ( A state that once entered cannot be exited)
Sneak path (an event is accepted when it should not be)
Trap door (the implementation accepts undefined events)
The Role of State Graphs in Software Testing
State Graphs provide framework for a model testing, where a State Graph is executed or
simulated with event sequences as test cases, before starting the actual implementation phase.
State Graphs specify system specification and support for testing the system implementation
against the system specification. State testing is primarily a functional testing tool which is
very effective when used in the early phases of design. With the help of State Graphs we can
generate test cases based on following steps:
Explicit mapping shall be done between the elements of the State Graph (states, events,
actions, transitions, guards) and the elements of the implementation (e.g., classes,
objects, attributes, messages, methods, expressions)
Ensure that the current state of the State Graph underlying the implementation must be
checkable, either by the runtime environment or by the implementation itself (built-in
tests with, e.g., assertions and class invariants)
Test Design Strategies for State Graph based Testing
Test cases derived from State Graph are sequence of input events. In state graphs, exhaustive
test case designing in order to execute every path at least once is impossible and unpractical.
As such, test cases using state graph model can be designed using following notions or rules:
All states coverage is achieved when each state of the State Graph is exercised at least
once during testing. This is usually not a sufficient level of coverage, because behaviour
faults are only accidentally found. If there is a bug in a transition between a specific state
pair, it can be missed even if all states coverage is reached.
All-events coverage: Each event of the State Graph is included in the test suite (is part of
at least one test case)
All-actions coverage: Each action is executed at least once
All-transitions coverage: All-transitions coverage is achieved when the test executes
every transition in the model at least once. This automatically entails also all states
coverage. Reaching all transitions coverage doesn’t require that any specific sequence is
executed, as long as all transitions are executed once. A bug that is revealed only when a
specific sequence of transitions is executed is missed even in this coverage level. The
coverage can be increased by requiring All n-transition coverage, meaning that all
possible transition sequences of n or more transitions are included in the test suite.
All n-transition sequences:
o Every transition sequence generated by n events is exercised at least once
o All transitions = all 1-transition sequences
o All n-transition sequences implies (subsumes) all (n-1)-transition sequences
All round-trip paths: every sequence of transitions beginning and ending in the same state
is exercised at least once
What is State Transition Testing?
State Transition testing, a black box testing technique, in which outputs are triggered by
changes to the input conditions or changes to 'state' of the system. In other words, tests are
designed to execute valid and invalid state transitions
When to use?
When we have sequence of events that occur and associated conditions that apply to
those events
When the proper handling of a particular event depends on the events and conditions that
have occurred in the past
It is used for real time systems with various states and transitions involved
Deriving Test cases:
Understand the various state and transition and mark each valid and invalid state
Defining a sequence of an event that leads to an allowed test ending state
Each one of those visited state and traversed transition should be noted down
Steps 2 and 3 should be repeated until all states have been visited and all transitions
traversed
For test cases to have a good coverage, actual input values and the actual output values
have to be generated
Advantages:
Allows testers to familiarise with the software design and enables them to design tests
effectively.
It also enables testers to cover the unplanned or invalid states.
The tests are derived from the above state and transition and below are the possible scenarios
that need to be tested..
What is Static Testing?
Static Testing, a software testing technique in which the software is tested without executing
the code. It has two parts as listed below:
Review - Typically used to find and eliminate errors or ambiguities in documents such as
requirements, design, test cases, etc.
Static analysis - The code written by developers are analysed (usually by tools) for
structural defects that may lead to defects.
Static Analysis - By Tools:
Following are the types of defects found by the tools during static analysis:
A variable with an undefined value
Inconsistent interface between modules and components
Variables that are declared but never used
Unreachable code (or) Dead Code
Programming standards violations
Security vulnerabilities
Syntax violations
What is Statistical Testing (ST)?
Statistical Testing makes use of statistical methods to determine the reliability of the
program. Statistical testing focuses on how faulty programs can affect its operating
conditions.
How to perform ST?
Software is tested with the test data that statistically models the working environment.
Failures are collated and analyzed.
From the computed data, an estimate of program's failure rate is calculated.
A Statistical method for testing the possible paths is computed by building an algebraic
function.
Statistical testing is a bootless activity as the intent is NOT to find defects.
You can use State Table to determine invalid system transitions. In a state Table, all the valid
states are listed on the left side of the table, and the events that cause them on the top. Each
cell represents the state system will move to when the corresponding event occurs.
Testability Tips
In order to design testability we need to build explicit state diagrams. Also, testability is easy
if the State Graph is designed using only two states.
Also, good amount of effort shall be directed by programmers towards identifying what type
of behaviours shall be considered to arrive at state graphs and what behaviours shall be
ignored. If programmers ignore this and arrive at state graph that is quite comfortable to work
with, then the very purpose of using state graphs as the basis for model based testing is beaten
since in model based testing there is a need to identify relevant states, inputs, and transitions
and ignoring irrelevant states, inputs, and transitions with a specific rationale behind it.
State graph is an advanced functional testing technique. Concepts of state graph help us in
building state graph model from specifications in order to perform model based testing. It is
essential a state graph shall be good. In order to ensure that the state graph we arrived at is
good – it shall be verified to check whether state graph that is modelled from specifications is
correct, complete and consistent enough for implementation of testing. State graph based
testing do not support exhaustive testing. Also, it is very difficult to design state graph for
complex and larger systems. As such state graphs are not good candidates for designing
exhaustive testing and also, shall be considered for designing test cases of complex and larger
systems.
Software Testability is a non-functional requirement that tell us about the ease with which we
can test the software. It should be added in software so that testcases and test scripts can be
executed thoroughly. Formally, “The extent to which a software system or its component
enables the setting up of test criteria and performance of tests to conclude whether those
criteria have been met or not”.
“Low Software Testability” in lot of circumstances degrades the software slowly as it may
not be detected at once; the testers, unaware of the fact, may consider wrong reasons and to
handle the problem may recommend numerous solutions like extending work hours,
assigning more resources, expensive automation tools, risk based testing, need for better
estimation and planning, etc. without the proper understanding the problem. This tends to
aggravate the situation, as the real problem will remain unfocused.
Software Testability is a prerequisite for software development as any SDLC encompasses
requirements gathering, analysis, design, coding, testing, implementation, and maintenance.
Complete execution of the test scripts can only be ensured if the application that is being
developed is significantly testable. Once decent test coverage is applied, most of the defects
will be uncovered and fixed before the product goes live in market which, in turn will result
in lesser issues being reported by the end users.
Graph Matrices:
Graph Matrices and Applications: Motivational Overview
The Problem with Pictorial Graphs
Graphs were introduced as an abstraction of software structure. There
are many other kinds of graphs that are useful in software testing. Whenever
a graph is used as a model, sooner or later we trace paths through it to find a
set of covering paths, a set of values that will sensitize paths, the logic
function that controls the flow, the processing time of the routine, the
equations that define a domain, whether the routine pushes or pops, or
whether a state is reachable or not.
Tool Building
If you build test tools or want to know how they work, sooner or later
you’ll be implementing or investigating analysis routines based on these
methods—or you should be. Think about how a naive tool builder would go
about finding a property of all paths (a possibly infinite number) versus how
one might do it based on the methods was graphical and it’s hard to build
algorithms over visual graphs. The properties of graph matrices are
fundamental to test tool building.
Doing and Understanding Testing Theory
We talk about graphs in testing theory, but we prove theorems about
graphs by proving theorems about their matrix representations. Without the
conceptual apparatus of graph matrices, you will be blind too much of testing
theory, especially those parts that lead to useful algorithms.
The Basic Algorithms
This is not intended to be a survey of graph-theoretic algorithms
based on the matrix representation of graphs. It’s intended only to be a basic
toolkit. The basic toolkit consists of:
1. Matrix multiplication, which is used to get the path expression
from every node to every other node.
2. A partitioning algorithm for converting graphs with loops into
loop-free graphs of equivalence classes.
The Matrix of a Graph:
Basic Principles
A graph matrix is a square array with one row and one column for
every node in the graph. Each row-column combination corresponds to a
relation between the node corresponding to the row and the node
corresponding to the column. The relation, for example, could be as simple
as the link name, if there is a link between the nodes. Observe the following:
1. The size of the matrix (i.e., the number of rows and columns)
equals the number of nodes.
2. There is a place to put every possible direct connection or link
between any node and any other node.
3. The entry at a row and column intersection is the link weight of
the link (if any) that connects the two nodes in that direction.
A Simple Weight
The simplest weight we can use is to note that there is or isn’t a
connection. Let “1” mean that there is a connection and “0” that there isn’t.
The arithmetic rules are:
1 + 1 = 1, 1 + 0 = 1, 0 + 0 = 0,
1 × 1 = 1, 1 × 0 = 0, 0 × 0 = 0.
A matrix with weights defined like this is called a connection matrix.
The connection matrix for is obtained by replacing each entry with I if there
is a link and 0 if there isn’t. As usual, to reduce clutter we don’t write down
0 entries. Each row of a matrix (whatever the weights) denotes the outlinks
of the node corresponding to that row, and each column denotes the inlinks
corresponding to that node. A branch node is a node with more than one
nonzero entry in its row.
Relations
This isn’t a section on aunts and uncles but on abstract relations that
can exist between abstract objects, although family and personal relations
can also be modeled by abstract relations, if you want to. A relation is a
property that exists between two (usually) objects of interest. We’ve had
many examples of relations in this book. Here’s a sample, where a and b
denote objects and R is used to denote that a has the relation R to b:
1. “Node a is connected to node b” or aRb where “R” means “is connected to.”
2. “a >= b” or aRb where “R” means “greater than or equal.”
3. “a is a subset of b” where the relation is “is a subset of.”
4. “It takes 20 microseconds of processing time to get from
node a to node b.” The relation is expressed by the number 20.
Properties of Relations
General
If that’s all we ask, then our relation arithmetic is too weak to
be useful. The following sections concern some properties of relations that
have been found to be useful. Any given relation may or may not have these
properties, in almost any combination.
Transitive Relations
A relation R is transitive if aRb and bRc implies aRc. Most relations
used in testing are transitive. Examples of transitive relations include: is
connected to, is greater than or equal to, is less than or equal to, is a relative
of, is faster than, is slower than, takes more time than, is a subset of,
includes, shadows, is the boss of.
Reflexive Relations
A relation R is reflexive if, for every a, aRa. A reflexive relation is
equivalent to a self- loop at every node. Examples of reflexive relations
include: equals, is acquainted with (except, perhaps, for amnesiacs), is a
relative of. Examples of irreflexive relations include: not equals, is a friend
of (unfortunately), is on top of, is under.
Symmetric Relations
A relation R is symmetric if for every a and b, aRb implies bRa. A
symmetric relation means that if there is a link from a to b then there is also
a link from b to a; which furthermore means that we can do away with
arrows and replace the pair of links with a single undirected link. A graph
whose relations are not symmetric is called a directed graph because we
must use arrows to denote the relation’s direction. A graph over a symmetric
relation is called an undirected graph. The matrix of an undirected graph is
symmetric (aij = aji for all i, j) Equivalence Relations
An equivalence relation is a relation that satisfies the reflexive, transitive,
and symmetric properties. Numerical equality is the most familiar example
of an equivalence relation. If a set of objects satisfy an equivalence relation,
we say that they form an equivalence class over that relation.
Partial Ordering Relations
A partial ordering relation satisfies the reflexive, transitive, and
antisymmetric properties. Partial ordered graphs have several important
properties: they are loop-free, there is at least one maximum element, there is
at least one minimum element, and if you reverse all the arrows, the resulting
graph is also partly ordered. A maximum element a is one for which the
relation xRa does not hold for any other element x.
The Powers of a Matrix
Principles
Each entry in the graph’s matrix (that is, each link) expresses a
relation between the pair of nodes that corresponds to that entry. It is a direct
relation, but we are usually interested in indirect relations that exist by virtue
of intervening nodes between the two nodes of interest. Squaring the matrix
(using suitable arithmetic for the weights) yields a new matrix that expresses
the relation between each pair of nodes via one intermediate node under the
assumption that the relation is transitive.
Matrix Powers and Products
Given a matrix whose entries are aij, the square of that matrix is obtained by
replacing every entry with more generally, given two matrices A and B, with
entries aik and bkj, respectively, their product is a new matrix C, whose
entries are cij, where:
The indexes of the product [C32] identify, respectively, the row of the first
matrix and the column of the second matrix that will be combined to yield
the entry for that product in the product matrix.
The Set of All Paths
Our main objective is to use matrix operations to obtain the set of all
paths between all nodes or, equivalently, a property (described by link
weights) over the set of all paths from every node to every other node, using
the appropriate arithmetic rules for such weights. The set of all paths
between all nodes is easily expressed in terms of matrix operations. It’s
given by the following infinite series of matrix powers: This is an eloquent,
but practically useless, expression. Let I be an n by n matrix, where n is the
number of nodes. Let I’s entries consist of multiplicative identity elements
along the principal diagonal. For link names, this can be the number “1.” For
other kinds of weights, it is the multiplicative identity for those weights. The
above product can be re-phrased as:
A (I + A + A2 + A3 + A4 . . . A∞),
But often for relations, A + A = A, (A + I)2 = A2 +
A +A + I A2 + A + I Furthermore, for any finite n,
(A + I)n = I + A + A2 + A3 . . . An
Loops
Every loop forces us into a potentially infinite sum of matrix powers. The
way to handle loops is similar to what we did for regular expressions. Every
loop shows up as a term in the diagonal of some power of the matrix—the
power at which the loop finally closes—or, equivalently, the length of the
loop. The impact of the loop can be obtained by preceding every element in
the row of the node at which the loop occurs by the path expression of the
loop term starred and then deleting the loop term.
Partitioning Algorithm (BEIZ71, SOHO84)
Consider any graph over a transitive relation. The graph may have loops. We
would like to partition the graph by grouping nodes in such a way that every
loop is contained within one group or another. Such a graph is partly
ordered. There are many used for an algorithm that does that:
1. We might want to embed the loops within a subroutine so as to
have a resulting graph which is loop-free at the top level.
2. Many graphs with loops are easy to analyze if you know where to break the
loops.
Breaking Loops and Applications
How do you find the point at which to break the loops? Consider the
matrix of a strongly connected subgraph. If there are entries on the principal
diagonal, then start by breaking the loop for those links. Now consider
successive powers of the matrix. At some power or another, a loop is
manifested as an entry on the principal diagonal. Furthermore, the regular
expression over the link names that appears in the diagonal entry tells you all
the places you can or must break the loop.
Node-Reduction Algorithm (General)
The matrix powers usually tell us more than we want to know about
most graphs. In the context of testing, we’re usually interested in
establishing a relation between two nodes — typically the entry and exit
nodes—rather than between every node and every other node. In a
debugging context it is unlikely that we would want to know the path
expression between every node and every other node; there also, it is the
path expression or some other related expression between a specific pair of
nodes that is sought.
Some Matrix Properties
If you numbered the nodes of a graph from 1 to n, you would not expect that
the behavior of the graph or the program that it represents would change if
you happened to number the nodes differently. Node numbering is arbitrary
and cannot affect anything. The equivalent to renumbering the nodes of a
graph is to interchange the rows and columns of the corresponding matrix.
Say that you wanted to change the names of nodes i and j to j and i,
respectively.
The first step in the Node-Reduction Algorithm is the most
complicated one: eliminating a node and replacing it with a set of equivalent
links. The reduction is done one node at a time by combining the elements in
the last column with the elements in the last row and putting the result into
the entry at the corresponding intersection.
Applications
The path expression is usually the most difficult and complicated to
get. The arithmetic rules for most applications are simpler. In this section
we’ll redo applications from, using the appropriate arithmetic rules, but this
time using matrices rather than graphs. Refer back to the corresponding
examples in to follow the successive stages of the analysis.