Software Testing
Software Testing
Introduction:
Purpose of Testing:
Testing consumes atleast half of the time and work required to produce a functional program.
• MYTH: Good programmers write code without bugs. (Its wrong!!!)
• History says that even well written programs still have 1-3 bugs per hundred statements.
• The main purpose of testing is to catch bugs.
• Productivity and Quality in software:
  ◦    In production of comsumer goods and other products, every
       manufacturing stage is subjected to quality control and testing from component to final
       stage.
  ◦    If flaws are discovered at any stage, the product is either discarded or cycled back for
       rework and correction.
  ◦    Productivity is measured by the sum of the costs of the material, the rework, and the
       discarded components, and the cost of quality assurance and testing.
Testing and Test Design are parts of quality assurance should also focus on bug prevention. A
prevented bug is better than a detected and corrected bug.
Phases in a tester's mental life can be categorised into the following 5 phases:
  1.   Phase 0: (Until 1956: Debugging Oriented) There is no difference between testing and
       debugging. Phase 0 thinking was the norm in early
       days of software development till testing emerged as a discipline.
  2.   Phase 1: (1957-1978: Demonstration Oriented) The purpose of testing here is to show that
       software works. Highlighted during the late 1970s. This failed because the probability of
       showing that software works 'decreases' as testing increases. i.e. The more you test, the more
       likely you’ll find a bug.
  3.   Phase 2: (1979-1982: Destruction Oriented) The purpose of testing is to show that software
       doesnt work. This also failed because the software will never get released as you will find
       one bug or the other. Also, a bug corrected may also lead to another bug.
  4.   Phase 3: (1983-1987: Evaluation Oriented) The purpose of testing is not to prove anything
       but to reduce the perceived risk of not working to an acceptable value (Statistical Quality
       Control). Notion is that testing does improve the product to the extent that testing catches
       bugs and to the extent that those bugs are fixed. The product is released when the confidence
       on that product is high enough. (Note:This is applied to large software products with
       millions of code and years of use.)
  5.   Phase 4: (1988-2000: Prevention Oriented) Testability is the factor considered here. One
       reason is to reduce the labour of testing. Other reason is to check the testable and non-
                                                                                                   1
       testable code. Testable code has fewer bugs than the code that's hard to test. Identifying the
       testing techniques to test the code is the main key here.
• Testing Versus Debugging: Many people consider both as same. Purpose of testing is to show
  that a program has bugs. The purpose of testing is to find the error or misconception that led to
  the program's failure and to design and implement the program changes that correct the error.
• Debugging usually follows testing, but they differ as to goals, methods and most important
  psychology. The below tab le shows few important differences between testing and debugging.
 Testing                                        Debugging
 Testing starts with known conditions, uses     Debugging starts from possibly unknown intial
 predefined procedures and has predictable      conditions and the end can not be predicted except
 outcomes.                                      statistically.
 Testing can and should be planned, designed Procedure and duration of debugging cannot be so
 and scheduled.                              constrained.
 Testing is a demonstration of error or
                                                Debugging is a deductive process.
 apparent correctness.
                                                Debugging is the programmer's vindication
 Testing proves a programmer's failure.
                                                (Justification).
 Testing, as executes, should strive to be
                                                Debugging demands intutive leaps,
 predictable, dull, constrained, rigid and
                                                experimentation and freedom.
 inhuman.
 Much testing can be done without design        Debugging is impossible without detailed design
 knowledge.                                     knowledge.
 Testing can often be done by an outsider.      Debugging must be done by an insider.
 Much of test execution and design can be
 automated.
  •    Function Versus Structure: Tests can be designed from a functional or a structural point of
       view. In functional testing, the program or system is treated as a blackbox. It is subjected to
       inputs, and its outputs are verified for conformance to specified behaviour. Functional
       testing takes the user point of view- bother about functionality and features and not the
       program's implementation. Structural testing does look at the implementation details. Things
       such as programming style, control method, source language, database design, and coding
       details dominate structural testing.
  •    Both Structural and functional tests are useful, both have limitations, and both target
       different kinds of bugs. Functional tets can detect all bugs but would take infinite time to do
       so. Structural tests are inherently finite but cannot detect all errors even if completely
       executed.
  •    Designer Versus Tester: Test designer is the person who designs the tests where as the tester
       is the one actually tests the code. During functional testing, the designer and tester are
       probably different persons. During unit testing, the tester and the programmer merge into
       one person.
                                                                                                  2
  •    Tests designed and executed by the software designers are by nature biased towards
       structural consideration and therefore suffer the limitations of structural testing.
  •    Builder Versus Buyer: Most software is written and used by the same organization.
       Unfortunately, this situation is dishonest because it clouds accountability. If there is no
       separation between builder and buyer, there can be no accountability.
2. Buyer: Who pays for the system in the hope of profits from providing services.
3. User: Ultimate beneficiary or victim of the system. The user's interests are also guarded by.
  5.   Operator: Who has to live with the builders' mistakes, the buyers' murky (unclear)
       specifications, testers' oversights and the users' complaints.
Above figure is a model of testing process. It includes three models: A model of the environment, a
model of the program and a model of the expected bugs.
• ENVIRONMENT:
                                                                                                       3
  ◦    A Program's environment is the hardware and software required to
       make it run. For online systems, the environment may include communication lines, other
       systems, terminals and operators.
  ◦    The environment also includes all programs that interact with and are used to create the
       program under test - such as OS, linkage editor, loader, compiler, utility routines.
  ◦    Because the hardware and firmware are stable, it is not smart to blame the environment for
       bugs.
• PROGRAM:
  ◦    If simple model of the program doesnot explain the unexpected behaviour, we may have to
       modify that model to include more facts and details. And if that fails, we may have to
       modify the program.
• BUGS:
  ◦    Bugs are more insidious (deceiving but harmful) than ever we expect
       them to be.
  ◦    An unexpected test result may lead us to change our notion of what a bug is and our model
       of bugs.
  ◦    Some optimistic notions that many programmers or testers have about bugs are usually
       unable to test effectively and unable to justify the dirty tests most programs need.
  1.   Frequency: How often does that kind of bug occur? Pay more attention to the more frequent
       bug types.
  2.   Correction Cost: What does it cost to correct the bug after it is found? The cost is the sum of
       2 factors: (1) the cost of discovery (2) the cost of correction. These costs go up dramatically
       later in the development cycle when the bug is discovered. Correction cost also depends on
       system size.
  3.   Installation Cost: Installation cost depends on the number of installations: small for a single
       user program but more for distributed systems. Fixing one bug and distributing the fix could
       exceed the entire system's development cost.
  4.   Consequences: What are the consequences of the bug? Bug consequences can range from
       mild to catastrophic.
  1.   Mild: The symptoms of the bug offend us aesthetically (gently); a misspelled output or a
       misaligned printout.
2. Moderate: Outputs are misleading or redundant. The bug impacts the system's performance.
  3.   Annoying: The system's behaviour because of the bug is dehumanizing. E.g. Names are
       truncated orarbitarily modified.
  4.   Disturbing: It refuses to handle legitimate (authorized / legal) transactions. The ATM wont
       give you money. My credit card is declared invalid.
  5.   Serious: It loses track of its transactions. Not just the transaction itself but the fact that the
       transaction occurred. Accountability is lost.
  6.   Very Serious: The bug causes the system to do the wrong transactions. Instead of losing your
       paycheck, the system credits it to another account or converts deposits to withdrawals.
  7.   Extreme: The problems aren't limited to a few users or to few transaction types. They are
       frequent and arbitrary instead of sporadic infrequent) or for unusual cases.
                                                                                                       5
     8.     Intolerable: Long term unrecoverable corruption of the database occurs and the corruption is
            not easily discovered. Serious consideration is given to shutting the system down.
9. Catastrophic: The decision to shut down is taken out of our hands because the system fails.
     10. Infectious: What can be worse than a failed system? One that corrupt other systems even
         though it doesnot fall in itself ; that erodes the social physical environment; that melts
         nuclear reactors and starts war.
TAXONOMY OF BUGS:
• There is no universally correct way categorize bugs. The taxonomy is not rigid.
     •      A given bug can be put into one or another category depending on its history and the
            programmer's state of mind.
    Requirements and specifications developed from them can be incomplete ambiguous, or self-
contradictory. They can be misunderstood or impossible to understand.
The specifications that don't have flaws in them may change while the design is in progress. The
features are added, modified and deleted.
Requirements, especially, as expressed in specifications are a major source of expensive bugs.
The range is from a few percentage to more than 50%, depending on the application and
environment. What hurts most about the bugs is that they are the earliest to invade the system and
the last to leave.
2.Feature Bugs:
                                                                                                          6
case is easier to detect and correct. A wrong feature could have deep design implications.
-Removing the features might complicate the software, consume more resources, and foster more
bugs.
3.Feature Interaction Bugs:
Providing correct, clear, implementable and testable feature specifications is not enough.
Features usually come in groups or related features. The features of each group and the interaction
of features with in the group are usually well tested.
The problem is unpredictable interactions between feature groups or even between individual
features. For example, your telephone is provided with call holding and call forwarding. The
interactions between these two features may have bugs.
Every application has its peculiar set of features and a much bigger set of unspecified feature
interaction potentials and therefore result in feature interaction bugs.
Most feature bugs are rooted in human to human communication problems. One solution is to use
high-level, formal specification languages or systems.
Such languages and systems provide short term support but in the long run, does not solve the
problem.
The specification problem has been shifted to a higher level but not eliminated.
• Control and sequence bugs include paths left out, unreachable code, improper nesting of loops,
  loop- back or loop termination criteria incorrect, missing process steps, duplicated processing,
  unnecessary processing, GOTO's, ill- conceived (not properly planned) switches, sphagetti code,
  and worst of all, pachinko code.
• One reason for control flow bugs is that this area is amenable (supportive) to theoritical treatment.
  Most of the control flow bugs are easily tested and caught in unit testing.
• Another reason for control flow bugs is that use of old code especially ALP & COBOL code are
  dominated by control flow bugs.
  Control and sequence bugs at all levels are caught by testing, especially structural testing, more
  specifically path testing combined with a bottom line functional test based on a specification.
2. Logic Bugs:
                                                                                                     7
         •      Bugs in logic, especially those related to misundertanding how case statements and
               logic operators behave singly and combinations
         •     If the bugs are parts of logical (i.e. boolean) processing not related to control flow,
               they are characterized as processing bugs.
         •     If the bugs are parts of a logical expression (i.e control-flow statement) which is used
               to direct the control flow, then they are categorized as control- flow bugs.
3. Processing Bugs:
4, Initialization Bugs:
        Initialization bugs are common. Initialization bugs can be improper and superfluous.
Superfluous bugs are generally less harmful but can affect performance. Typical initialization bugs
include: Forgetting to initialize the variables before first use, assuming that they are initialized
elsewhere, initializing to the wrong format, representation or type etc Explicit declaration of all
variables, as in Pascal, can reduce some initialization problems.
3.DATA BUGS:
  •    Data bugs include all bugs that arise from the specification of
       data objects, their formats, the number of such objects, and their initial values.
       Data Bugs are atleast as common as bugs in code, but they are foten treated as if they didnot
       exist at all.
       Code migrates data: Software is evolving towards programs in which more and more of the
       control and processing functions are stored in tables.
  •    Because of this, there is an increasing awareness that bugs in code are only half the battle
       and the data problems should be given equal attention.
                                                                                                         8
4 CODING BUGS:
Coding errors of all kinds can create any of the other kind of bugs.
       •      Syntax errors are generally not important in the scheme of things if the source
              language translator has adequate syntax checking.
       •       If a program has many syntax errors, then we should expect many logic and coding
              bugs.
       •       The documentation bugs are also considered as coding bugs which may mislead the
              maintenance programmers.
       1.     External Interfaces: The external interfaces are the means used to communicate with
              the world.
• The primary design criterion for an interface with outside world should be robustness.
            • The external environment is fixed and the system must adapt to it but the
              internal environment, which consists of interfaces with other components,
              can be negotiated.
3. Hardware Architecture:
 •   The remedy for hardware architecture and interface problems is two fold: (1) Good
     Programming and Testing (2) Centralization of hardware interface software in
     programs written by hardware interface specialists.
                                                                                                  9
4.   Operating System Bugs:
5. Software Architecture:
• Routines can pass unit and integration testing without revealing such bugs.
      •    Many of them depend on load, and their symptoms emerge only when the
           system is stressed.
      •    Sample for such bugs: Assumption that there will be no interrupts, Failure to
           block or un block interrupts, Assumption that memory and registers were
           initialized or not initialized etc
      •    Careful integration of modules and subjecting the final system to a stress test
           are effective methods for these bugs.
      •    External mass storage units such as discs, are subdivided into memory
           resource pools.
                                                                                       10
         •    Some resource management and usage bugs: Required resource not
             obtained, Wrong resource used, Resource is already in use, Resource dead
             lock etc
8. Integration Bugs:
  •   Integration bugs are bugs having to do with the integration of, and with the
      interfaces between, working and tested components.
 The integration bugs do not constitute a big bug category(9%) they are expensive
category because they are usually caught late in the game and because they force changes
in several components and/or data structures.
9. System Bugs:
 System bugs covering all kinds of bugs
that cannot be ascribed to a component or to their simple interactions, but result from the
totality of interactions between many components such as programs, data, hardware, and
the operating systems.
  •   There can be no meaningful system testing until there has been thorough
      component and integration testing.
  •   System bugs are infrequent(1.7%) but very important because they are often found
      only after the system has been fielded.
         •   Testing: testers have no immunity to bugs. Tests require complicated scenarios and
             databases.
• They require code or the equivalent to execute and consequently they can have bugs.
                                                                                             11
       •    Test criteria: if the specification is correct, it is correctly interpreted and
            implemented, and a proper test has been designed; but the criterion by which the
            software's behavior is judged may be incorrect or impossible. So, a proper test
            criteria has to be designed. The more complicated the criteria, the likelier they are to
            have bugs.
               1.   Test Debugging: The first remedy for test bugs is testing and debugging the
                    tests. Test debugging, when compared to program debugging, is easier
                    because tests, when properly designed are simpler than programs and donot
                    have to make concessions to efficiency.
               2.   Test Quality Assurance: Programmers have the right to ask how quality in
                    independent testing is monitored.
PATH TESTING:
 ◦   Path Testing is the name given to a family of test techniques based on judiciously selecting a
     set of test paths through the program.
 ◦   If the set of paths are properly chosen then we have achieved some measure of test
     thoroughness. For example, pick enough paths to assure that every source statement has
     been executed at least once.
◦ Path testing techniques are the oldest of all structural test techniques.
◦ Path testing is most applicable to new software for unit testing. It is a structural technique.
                                                                                                   12
Assumptions:
Observations:
The control flow graph is a graphical representation of a program's control structure. It uses the
elements named process blocks, decisions, and junctions.
Flow Graph Elements:A flow graph contains four different types of elements.
(1) Process Block (2) Decisions (3) Junctions (4) Case Statements
1. ProcessBlock:
  •    It is a sequence of statements such that if any one of statement of the block is executed, then
       all statement thereof are executed.
  •     Formally, a process block is a piece of straight line code of one statement or hundreds of
       statements.
  •    A process has one entry and one exit. It can consists of a single statement or instruction, a
       sequence of statements or instructions, a single entry/exit subroutine, a macro or function
       call, or a sequence of these.
2. Decisions:
3. Case statements
• A junction is a point in the program where the control flow can merge.
                                                                                                   13
• Examples of junctions are: the target of a jump or skip instruction in ALP, a label that is a target
  of GOTO.
         ◦     The flowchart focuses on process steps, where as the flow graph focuses on control
               flow of the program.
         ◦     The act of drawing a control flow graph is a useful tool that can help us clarify the
               control flow and data flow issues.
                                                                                                   14
PATH TESTING - PATHS, NODES AND LINKS:
◦ A path may go through several junctions, processes, or decisions, one or more times.
◦ The segment is a link - a single process that lies between two nodes.
         ◦    The length of path measured by the number of links in it and not by the number of
              the instructions or statements executed along that path.
◦ The name of a path is the name of the nodes along the path.
◦ There are many paths between the entry and exit of a typical routine.
         ◦    Every decision doubles the number of potential paths. And every loop multiplies the
              number of potential paths by the
              number of different iteration values possible for the loop.
3. Exercise every branch and case statement, in each direction at least once
         ◦    Any testing strategy based on paths must at least both exercise every instruction and
              take branches in all directions.
         ◦    A set of tests that does this is not complete in an absolute sense, but it is complete in
              the sense that anything less
              must leave something untested.
• Execute all possible control flow paths through the program: typically, this is restricted to all
  possible entry/exit paths through the program.
                                                                                                    15
• If we achieve this prescription, we are said to have achieved 100% path coverage. This is the
  strongest criterion in the path testing strategy family: it is generally impossible to achieve.
  •    Execute all statements in the program at least once under some test. If we do enough tests to
       achieve this, we are said to have achieved 100% statement coverage.
  •    This is the weakest criterion in the family: testing less than this for new software is
       unconscionable (unprincipled or can not be accepted) and should be criminalized.
  •    Execute enough tests to assure that every branch alternative has been exercised at least once
       under some test.
  •    If we do enough tests to achieve this prescription, then we have achieved 100% branch
       coverage.
  •    For structured software, branch testing and therefore branch coverage strictly includes
       statement
       coverage.
• PREDICATE: The logical function evaluated at a decision is called Predicate. The direction taken
  at a decision depends on the value of decision variable. Some examples are: A>0, x+y>=90.......
• PATH PREDICATE: A predicate associated with a path is called a Path Predicate. For example, "x
  is greater than zero", "x+y>=90", "w is either negative or equal to 10 is true" is a sequence of
  predicates whose truth values will cause the routine to take a specific path.
• If you cant find a solution to any of the sets of inequalities, the path is un achievable.
PATH SENSITIZATION:
• The act of finding a set of solutions to the path predicate expression is called PATH
  SENSITIZATION.
                                                                                                 16
PATH PREDICATE EXPRESSIONS:
• A path predicate expression is a set of boolean expressions, all of which must be satisfied to
  achieve the
  selected path.
  Example:
X1+3X2+17>=0
X3=17
X4-X1>=14X2
Any set of input values that satisfy all of the conditions of the path predicate expression will force
the routine to the path.
Some times a predicate can have an OR in it.
Example:
A: X5 > 0
B: X1 + 3X2 + 17 >= 0 C: X3 = 17
D: X4 - X1 >= 14X2
E: X6 < 0
B: X1 + 3X2 + 17 >= 0 C: X3 = 17
D: X4 - X1 >= 14X2
TESTING BLINDNESS:
Testing Blindness is a pathological (harmful) situation in which the desired path is achieved for the
wrong reason.
There are three types of Testing Blindness:
1. Assignment Blindness:
   •    Assignment blindness occurs when the buggy predicate appears to work correctly because
        the specific value chosen for an assignment statement works with both the correct and
        incorrect predicate.
   •    For Example:
    •       If the test case sets Y=1 the desired path is taken in either case, but there is still a bug.
Correct Buggy
X= 7 X= 7
........ ........
If the test case sets Y=1 the desired path is taken in either case, but there is still a bug.
2. EqualityBlindness:
• Equality blindness occurs when the path selected by a prior predicate results in a value that works
  both for the correct and buggy predicate.
                                                                                                            17
• For Example:
Correct Buggy
                              if Y = 2
 if Y = 2 then ........
                              then ........
 if X+Y > 3 then ...
                              if X > 1 then ...
• The first predicate if y=2 forces the rest of the path, so that for any positive value of x. the path
  taken at the second predicate will be the same for the correct and buggy version.
  3.Self Blindness:
  Self blindness occurs when the buggy predicate is a multiple of the correct predicate
  and as a result is indistinguishable along that path. For Example:
 Correct                  Buggy
 X= A                     X= A
 ........                 ........
 if X-1 > 0               if X+A-2 > 0
 then ...                 then ...
 The assignment (x=a) makes the predicates multiples of each other, so the direction taken is the
 same for the correct and buggy version.
PATH INSTRUMENTATION:
  •         Path instrumentation is what we have to do to confirm that the outcome was achieved by the
            intended path.
  •         Co-incidental Correctness: The coincidental correctness stands for achieving the desired
            outcome for wrong reason.
  •
            Figure 2.11: Coincidental Correctness
            The above figure is an example of a routine that, for the (unfortunately) chosen input value
            (X = 16), yields the same outcome (Y = 2) no matter which case we select. Therefore, the
            tests chosen this way will not tell us whether we have achieved coverage. For example, the
            five cases could be totally jumbled and still the outcome would be the same. Path
            Instrumentation is what we have to do to confirm that the outcome was achieved by the
            intended path.
                •    If we run the tested routine under a trace, then we have all the information we
                     need to confirm the outcome and, furthermore, to confirm that it was
                     achieved by the intended path.
                •    The trouble with traces is that they give us far more information than we
                     need. In fact, the typical trace program provides so much information that
                     confirming the path from its massive output dump is more work than
                     simulating the computer by hand to confirm the path.
                •    Instrument the links so that the link's name is recorded when the link is
                     executed.
                •     The succession of letters produced in going from the routine's entry to its
                     exit should, if there are no bugs, exactly correspond to the path name.
Why Single Link Markers aren't enough: Unfortunately, a single link marker may not do the trick
because links can be chewed by open bugs.
19