Understanding Software Testing Methods
Understanding Software Testing Methods
Software Testing
Software testing is a very important, challenging and essential activity. It starts along with the
design of SRS document and ends at the delivery of software product to the customer. It consumes
significant effort and maximum time of software development life cycle (without including the
maintenance phase). The significant effort may be from one third to one half of the total effort
expended till the delivery of the software product. We cannot imagine to deliver a software
product without adequate testing. The existing testing techniques help us to do adequate testing.
However, adequate testing has different meaning to different software testers.
348
Software Testing 349
This definition motivates us to select those inputs which have higher probability of finding
faults, although the definition is also not complete because it focuses only on the execution of
the program. Nowadays, attention is also given to the activities like reviewing the documents
and programs. Reviewing the documents (like SRS and SDD) helps us to find a good number
of faults in the early phases of software development. Hence, testing is divided into two parts:
verification and validation. Therefore, the most appropriate definition of software testing is:
Software testing is the process of verifying the outcomes of every phase of software development
and validating the program by executing it with the intention of finding faults.
In the initial days of programming, testing was primarily validation oriented but nowadays both
are equally important and carried out in most of the software organizations.
9.1.1 Verification
Software verification is also known as static testing where testing activities are carried out
without executing the program. It may include inspections, walkthroughs and reviews where
documents and programs are reviewed with the purpose of finding faults. Hence, verification
is the process of reviewing (rechecking) documents and program with the intention of finding
faults. As per the IEEE (2001):
The verification is the process of evaluating the system or component to determine whether the
products of a given development phase satisfy the conditions imposed at the start of that phase.
9.1.2 Validation
Software validation is also known as dynamic testing where the program is executed with given
input(s). Hence, validation involves execution of the program and usually exposes symptoms of
errors. As per the IEEE (2001):
The validation is the process of evaluating a system or component during or at the end of
development process to determine whether it satisfies the specified requirements.
Validation activities are carried out with the execution of the program. We experience failures
and reasons of such failures are identified.
Software testing includes both verification and validation. Both are important and
complementary to each other. Effective verification activities find a good number of faults in
the early phases of software development. Removing such faults will definitely provide better
foundations for the implementation/construction phase. Validation activities are possible only
after the implementation of module/program, but verification activities are possible in every
phase of software development.
the software professionals are convinced about the importance and usefulness of verification
techniques. They also believe that a good quality software product can be produced only after the
effective implementation of verification techniques. Many verification techniques are commonly
used in practice and some of them are discussed in the following subsections.
9.2.2 Walkthroughs
Walkthrough is a group activity for reviewing the documents and programs. It is a more formal
and systematic technique than per reviews. A group of two to seven persons is constituted for
the purpose of reviewing. The author of the document presents the document to the group during
walkthroughs conducted in a conference room. The author may use any display mechanism (like
whiteboard, projector) for presentation. Participants are not expected to prepare anything prior
to such a meeting. Only the presenter who happens to be the author of the document prepares
for the walkthrough. Documents and/or programs are distributed to every participant and the
author presents the contents to all to make them understand. All participants are free to ask
questions and write their observations on any display mechanism in such a way that everyone
can see it. The observations are discussed thoroughly amongst the participants and changes
are suggested accordingly. The author prepares a detailed report as per suggested changes. The
report is studied, changes are approved and documents/programs are modified.
The limitations of such a technique are the non-preparation of participants prior to meeting
and presentation of documents by their author(s). The author(s) may unnecessarily highlight
some areas and hide a few critical areas. Participants may also not be able to ask critical and
penetrating questions. Walkthroughs may create awareness amongst participants and may also
find a few important faults. This technique is more expensive but systematic than peer reviews
and applicable to any size of software project.
9.2.3 Inspections
This technique is more formal, systematic and effective. There are many names for this
technique like formal reviews, formal technical reviews and inspections. The most popular
Software Testing 351
name is inspection and is different from peer reviews and walkthroughs. A group of three to
six persons is constituted. The author of the document is not the presenter. An independent
presenter is appointed for this specific purpose who prepares and understands the document.
This preparation provides a second eye on the document(s) prior to meeting. The documents(s)
is/are distributed to every participant in advance to give sufficient time for preparation. Rules
of the meeting are prepared and circulated to all participants in advance to make them familiar
with the framework of the meeting. The group is headed by an impartial moderator who should
be a senior person to conduct the meetings smoothly. A recorder is also engaged to record the
proceedings of the meetings.
The presenter presents the document(s) in the meeting and makes everyone comfortable
with the document(s). Every participant is encouraged to participate in the deliberations as
per modified rules. Everyone gets time to express his/her views, opinions about quality of
document(s), potential faults and critical areas. The moderator chairs the meeting, enforces the
discipline as per prescribed rules and respects views of every participant. Important observations
are displayed in a way that is visible to every participant. The idea is to consider everyone’s
views and not to criticize them. Many times, a checklist is used to review the document. After
the meeting, the moderator along with the recorder prepares a report and circulates it to all
participants. Participants may discuss the report with the moderator and suggest changes. A
final report is prepared after incorporating changes. The changes should be approved by the
moderator. Most of the organizations use inspections as a verification technique and outcomes
are very good. Many faults are generally identified in the early phases of software development.
This is a popular, useful and systematic technique and is effective for every type of document
and program. The comparison of all the three techniques is given in Table 9.1.
Verification is always more useful than validation due to its applicability in early phases
of software development. It finds those faults which may not be detected by any validation
technique. Verification techniques are becoming popular and more attention is given to such
techniques from the beginning of the software development.
352 Object-Oriented Software Engineering
Part II
(Contd.)
Software Testing 353
Table 9.2 Checklist for a good quality software (Contd.)
S. No. Description Yes/No/NA Comments
12. Do you want to delete any field in any form?
13. Do you want to add/delete any validity check?
14. Is readability of the document satisfactory?
15. Are non-functional requirements specified?
Actors, use cases and use case description
16. Are all the actors identified?
17. Are all the use cases determined?
18. Does the name of the use case represent the function it is
required to perform?
19. Are all the actors included in the use case description of each
use case?
20. Are you ready to accept identified use cases and their
descriptions?
21. Does the use case description include precondition?
22. Does the use case description include postcondition?
23. Is the basic flow in the use case complete?
24. Are all the alternative flows of the use case stated?
25. Are related use cases stated?
Characteristics of requirements
26. Are all requirements feasible?
27. Are requirements non-feasible due to technical problems?
28. Are requirements non-feasible due to inadequate resources?
29. Are a few requirements difficult to implement?
30. Are all requirements conveying only one meaning?
31. Are there conflicts amongst requirements?
32. Are all functional and non-functional requirement defined?
33. Are all use cases clearly understandable?
34. Are all forms available with adequate validity checks?
35. Are all requirements specified at a consistent level of detail?
36. Is consistency maintained throughout the document?
37. Are there any conflicts amongst requirements?
38. Are all defined requirements verifiable?
39. Are all stated requirements understandable?
40. Are redundant requirements identified?
41. Do you want to add a requirement?
42. Are all stated requirements written in a simple language?
(Contd.)
354 Object-Oriented Software Engineering
Part II
Part II
(Contd.)
356 Object-Oriented Software Engineering
Every dot of the input domain represents input(s) and every dot of the output domain
represents output(s). Every dot of the input domain has a corresponding dot in the output
domain. We consider valid and invalid inputs for the purpose of program execution and note the
behaviour in terms of observed outputs. Functional testing techniques provide ways to design
effective test cases to find errors in the program.
The technique selects only five values instead of 900 values to test the program. These
values of a are 100, 101, 550, 999, 1000 which cover the boundary portions of the input value
except one nominal value (say 550). The nominal value represents those values which are neither
on the boundary nor close to boundary. The number of test cases designed by this technique
is 4n + 1, where n is the number of input values. The test cases generated for the ‘square root’
program are shown in Table 9.5.
We consider a program ‘subtraction’ with two input values a and b and the output is the
subtraction of a and b. The ranges of input values are shown as:
100 a 1000
200 b 1200
The selected values for a and b are given as:
a = (100, 101, 550, 999, 1000)
b = (200, 201, 700, 1199, 1200)
358 Object-Oriented Software Engineering
Both inputs (a and b) are required for the execution of the program. The input domain is
shown in Figure 9.3 where any point within the rectangle is a legitimate input of the program.
The test cases are generated on the basis of ‘single fault’ assumption theory of reliability.
This theory assumes that failures are rarely the result of simultaneous occurrence of two (or
more) faults. Generally one fault is responsible for a failure. The implication of this theory is
that we select one input for any of the defined states (minimum, just above minimum, just below
maximum, maximum, nominal) and other input(s) as nominal values.
The test cases are 4n + 1 (i.e. 8 + 1 = 9) which are given in Table 9.6. The input values are
also shown graphically in Figure 9.3.
EXAMPLE 9.1 Consider a program to multiply and divide two numbers. The inputs may be
two valid integers (say a and b) in the range of [0, 100]. Generate boundary value analysis test
cases.
Solution Boundary value analysis test cases are given in Table 9.7.
Software Testing 359
Table 9.7 Boundary value analysis test cases for Example 9.1
Test case a b Expected output
1 0 50 0 0
2 1 50 50 0
3 50 50 2500 1
4 99 50 4950 1
5 100 50 5000 2
6 50 0 0 Divide by zero error
7 50 1 50 50
8 50 99 4950 0
9 50 100 5000 0
EXAMPLE 9.2 Consider a program which takes a date as an input and checks whether it is
a valid date or not. Its input is a triple of day, month and year with the values in the following
ranges:
1 month 12
1 day 31
2000 year 2070
Generate boundary value analysis test cases.
Solution Boundary value analysis test cases are given in Table 9.8.
Table 9.8 Boundary value test cases for program determining validity of date
Test case Month Day Year Expected output
1 1 15 2035 Valid date (1/15/2035)
2 2 15 2035 Valid date (2/15/2035)
3 6 15 2035 Valid date (6/15/2035)
4 11 15 2035 Valid date (11/15/2035)
5 12 15 2035 Valid date (12/15/2035)
6 6 1 2035 Valid date (6/1/2035)
7 6 2 2035 Valid date (6/2/2035)
8 6 30 2035 Valid date (6/30/2035)
9 6 31 2035 Invalid date
10 6 15 2000 Valid date (6/15/2000)
11 6 15 2001 Valid date (6/15/2001)
12 6 15 2069 Valid date (6/15/2069)
13 6 15 2070 Valid date (6/15/2070)
There are three extensions of boundary value analysis technique and are given below:
(i) Robustness testing
Two additional states ‘just below minimum’ and ‘just above maximum’ are added to see the
behaviour of the program with invalid input values. Invalid inputs are equally important and
may make the program fail when such inputs are given.
360 Object-Oriented Software Engineering
There are seven states in robustness testing and are given as:
1. Just below minimum (minimum–)
2. Minimum
3. Just above minimum (minimum+)
4. Nominal (average value)
5. Just below maximum (maximum–)
6. Maximum
7. Just above maximum (maximum+)
The total number of test cases generated for robustness testing is 6n + 1, where n is the number
of input values. Test cases for ‘subtraction’ program using robustness testing are 13 as given in
Table 9.9.
The input domain has four test cases which are outside; the other test cases lie in the
legitimate input domain as shown in Figure 9.4.
Figure 9.4 Input domain of ‘subtraction’ program for robustness test cases.
Software Testing 361
(ii) Worst case testing
This is another form of boundary value analysis where the single fault assumption theory of
reliability is rejected. Hence, a failure may also be the result of the occurrence of more than one
fault simultaneously. The result of this rejection is that one, two or all input values may have one
of the following states:
Minimum
Minimum+
Nominal (average value)
Maximum–
Maximum
In the worst case testing, the restriction of one input value at the above-mentioned states
and other input values nominal is removed. The implication is that the number of test cases
will increase from 4n + 1 test cases to 5n test cases, where n is the number of input values. The
‘subtraction’ program will have 52 = 25 test cases which are shown in Table 9.10.
The inputs given in Table 9.10 are graphically represented in Figure 9.5.
In the worst case testing, we select more number of test cases for completeness and
thoroughness. This is a more effort and time-consuming technique.
(iii) Robust worst case testing
Two more states are added to check the behaviour of the program with invalid inputs. These
two states are ‘just below minimum’ and ‘just above maximum’. The total number of test cases
generated by this technique is 7n. The subtraction program has 72 = 49 test cases which are given
in Table 9.11.
(Contd.)
Software Testing 363
Table 9.11 Robust worst test cases for ‘subtraction’ program (Contd.)
Boundary value analysis is a useful technique and may generate effective test cases. There
is a restriction that input values should be independent. It is not applicable for Boolean variables
because of only two available states—true and false. The technique is also easy to understand
and implement for any size of program.
EXAMPLE 9.3 Consider a program to multiply and divide two numbers as explained in
Example 9.1. Design the robust test cases and worst test cases for this program.
Solution Robust test cases are given in Table 9.12.
Table 9.12 Robust test cases for a program to multiply and divide two numbers
Test case a b Expected output
1 –1 50 Input values are out of range
2 0 50 0 0
3 1 50 50 0
4 50 50 2500 1
5 99 50 4950 1
6 100 50 5000 2
7 101 50 Input values are out of range
8 50 –1 Input values are out of range
9 50 0 0 Divide by zero error
10 50 1 50 50
11 50 99 4950 0
12 50 100 5000 0
13 50 101 Input values are out of range
Software Testing 365
Worst test cases are given in Table 9.13.
Table 9.13 Worst test cases for a program to multiply and divide two numbers
Test case a b Expected output
Multiply Divide
1 0 0 0 Undefined*
2 0 1 0 0
3 0 50 0 0
4 0 99 0 0
5 0 100 0 0
6 1 0 0 Divide by zero error
7 1 1 1 1
8 1 50 50 1
9 1 99 99 1
10 1 100 100 1
11 50 0 0 Divide by zero error
12 50 1 50 50
13 50 50 2500 1
14 50 99 4950 0
15 50 100 5000 0
16 99 0 0 Divide by zero error
17 99 1 99 99
18 99 50 4950 1
19 99 99 9801 1
20 99 100 9900 0
21 100 0 0 Divide by zero error
22 100 1 100 100
23 100 50 5000 2
24 100 99 9900 1
25 100 100 10,000 1
EXAMPLE 9.4 Consider the program for the determination of validity of the date as explained
in Example 9.2. Design the robust and worst test cases for this program.
Solution Robust test cases and worst test cases are given in Tables 9.14 and 9.15, respectively.
366 Object-Oriented Software Engineering
Table 9.14 Robust test cases for program for determining the validity of the date
Test case Month Day Year Expected output
1 0 15 2035 Invalid date
2 1 15 2035 Valid date (1/15/2035)
3 2 15 2035 Valid date (2/15/2035)
4 6 15 2035 Valid date (6/15/2035)
5 11 15 2035 Valid date (11/15/2035)
6 12 15 2035 Valid date (12/15/2035)
7 13 15 2035 Invalid date
8 6 0 2035 Invalid date
9 6 1 2035 Valid date (6/1/2035)
10 6 2 2035 Valid date (6/2/2035)
11 6 30 2035 Valid date (6/30/2035)
12 6 31 2035 Invalid date
13 6 32 2035 Invalid date
14 6 15 1999 Invalid date (out of range)
15 6 15 2000 Valid date (6/15/2000)
16 6 15 2001 Valid date (6/15/2001)
17 6 15 2069 Valid date (6/15/2069)
18 6 15 2070 Valid date (6/15/2070)
19 6 15 2071 Invalid date (out of range)
Table 9.15 Worst test cases for the program determining the validity of the date
Test case Month Day Year Expected output
1 1 1 2000 Valid date (1/1/2000)
2 1 1 2001 Valid date (1/1/2001)
3 1 1 2035 Valid date (1/1/2035)
4 1 1 2069 Valid date (1/1/2069)
5 1 1 2070 Valid date (1/1/2070)
6 1 2 2000 Valid date (1/2/2000)
7 1 2 2001 Valid date (1/2/2001)
8 1 2 2035 Valid date (1/2/2035)
9 1 2 2069 Valid date (1/2/2069)
10 1 2 2070 Valid date (1/2/2070)
11 1 15 2000 Valid date (1/15/2000)
12 1 15 2001 Valid date (1/15/2001)
13 1 15 2035 Valid date (1/15/2035)
14 1 15 2069 Valid date (1/15/2069)
(Contd.)
Software Testing 367
Table 9.15 Worst test cases for the program determining the validity of the date (Contd.)
Table 9.15 Worst test cases for the program determining the validity of the date (Contd.)
Table 9.16 Test cases of ‘square root’ program for input domain
Test case Input a Expected output
I1 500 22.36
I2 10 Invalid input
I3 1100 Invalid input
The output domain is also partitioned to generate equivalence classes. We generate the
following output domain equivalence classes:
O1 = {Square root of input value a}
O2 = {Invalid value}
Software Testing 371
The test cases for the output domain are given in Table 9.17. Some of the input and output
domain test cases may be the same.
Table 9.17 Test cases of ‘square root’ program for output domain
Test case Input a Expected output
O1 500 22.36
O2 1100 Invalid input
We consider the ‘subtraction’ program which takes two inputs a (range 100–1000) and b
(range 200–1200) and performs the subtraction of these two input values. On the basis of the
input domain, we generate the following equivalence classes:
(i) I1 = {100 a 1000 and 200 b 1200} (Both a and b are valid values)
(ii) I2 = {100 a 1000 and b < 200} (a is valid and b is invalid)
(iii) I3 = {100 a 1000 and b > 1200} (a is valid and b is invalid)
(iv) I4 = {a < 100 and 200 b 1200} (a is invalid and b is valid)
(v) I5 = {a > 1000 and 200 b 1200} (a is invalid and b is valid)
(vi) I6 = {a < 100 and b < 200} (Both inputs are invalid)
(vii) I7 = {a < 100 and b > 1200} (Both inputs are invalid)
(viii) I8 = {a > 1000 and b < 200} (Both inputs are invalid)
(ix) I9 = {a > 1000 and b > 1200} (Both inputs are invalid)
The input domain test cases are given in Table 9.18.
The test cases for the output domain are given in Table 9.19.
We have designed only one equivalence class for the valid input domain in both of the
above discussed examples. We could not partition the valid input domain due to simplicity of
the problem. However, programs are more complex and logic oriented. We may design more
valid input domain equivalence classes on the basis of logic and relationship. The design of
equivalence classes is subjective and two designers may design different classes. The objective
is to cover every functionality of the program which may further cover maximum portion of
the source code during testing. This technique is applicable at unit, integration system and
acceptance testing levels. This is a very effective technique if equivalence classes are designed
correctly and also reduces the number of test cases significantly.
EXAMPLE 9.5 Consider a program to multiply and divide two numbers. The inputs may be
two valid integers (say a and b) in the range of [0, 100]. Develop test cases using equivalence
class testing.
Solution The test cases are generated for output domain given in Table 9.20:
EXAMPLE 9.6 Consider the program for determining whether the date is valid or not. Identify
the equivalence class test cases for output and input domains.
Solution Output domain equivalence classes are:
O1 = {< Day, Month, Year > : Valid}
O2 = {< Day, Month, Year > : Invalid date if any of the inputs is invalid}
O3 = {< Day, Month, Year > : Input is out of range if any of the inputs is out of range}
The output domain test cases are given in Table 9.22.
I35 = {M4 and D2 and Y2} (Month is invalid, Day is valid and Year is valid)
I36 = {M5 and D2 and Y2} (Month is invalid, Day is valid and Year is valid)
I37 = {M4 and D3 and Y2} (Month is invalid, Day is valid and Year is valid)
I38 = {M5 and D3 and Y2} (Month is invalid, Day is valid and Year is valid)
I39 = {M4 and D4 and Y2} (Month is invalid, Day is valid and Year is valid)
I40 = {M5 and D4 and Y2} (Month is invalid, Day is valid and Year is valid)
I41 = {M1 and D5 and Y1} (Month is valid, Day is invalid and Year is valid)
I42 = {M1 and D6 and Y1} (Month is valid, Day is invalid and Year is valid)
I43 = {M2 and D5 and Y1} (Month is valid, Day is invalid and Year is valid)
I44 = {M2 and D6 and Y1} (Month is valid, Day is invalid and Year is valid)
I45 = {M3 and D5 and Y1} (Month is valid, Day is invalid and Year is valid)
I46 = {M3 and D6 and Y1} (Month is valid, Day is invalid and Year is valid)
I47 = {M1 and D5 and Y2} (Month is valid, Day is invalid and Year is valid)
I48 = {M1 and D6 and Y2} (Month is valid, Day is invalid and Year is valid)
I49 = {M2 and D5 and Y2} (Month is valid, Day is invalid and Year is valid)
I50 = {M2 and D6 and Y2} (Month is valid, Day is invalid and Year is valid)
I51 = {M3 and D5 and Y2} (Month is valid, Day is invalid and Year is valid)
I52 = {M3 and D6 and Y2} (Month is valid, Day is invalid and Year is valid)
I53 = {M1 and D1 and Y3} (Month is valid, Day is valid and Year is invalid)
I54 = {M1 and D1 and Y4} (Month is valid, Day is valid and Year is invalid)
I55 = {M2 and D1 and Y3} (Month is valid, Day is valid and Year is invalid)
I56 = {M2 and D1 and Y4} (Month is valid, Day is valid and Year is invalid)
I57 = {M3 and D1 and Y3} (Month is valid, Day is valid and Year is invalid)
I58 = {M3 and D1 and Y4} (Month is valid, Day is valid and Year is invalid)
I59 = {M1 and D2 and Y3} (Month is valid, Day is valid and Year is invalid)
I60 = {M1 and D2 and Y4} (Month is valid, Day is valid and Year is invalid)
I61 = {M2 and D2 and Y3} (Month is valid, Day is valid and Year is invalid)
I62 = {M2 and D2 and Y4} (Month is valid, Day is valid and Year is invalid)
I63 = {M3 and D2 and Y3} (Month is valid, Day is valid and Year is invalid)
I64 = {M3 and D2 and Y4} (Month is valid, Day is valid and Year is invalid)
I65 = {M1 and D3 and Y3} (Month is valid, Day is valid and Year is invalid)
I66 = {M1 and D3 and Y3} (Month is valid, Day is valid and Year is invalid)
I67 = {M2 and D3 and Y3} (Month is valid, Day is valid and Year is invalid)
I68 = {M2 and D3 and Y4} (Month is valid, Day is valid and Year is invalid)
I69 = {M3 and D3 and Y3} (Month is valid, Day is valid and Year is invalid)
I70 = {M3 and D3 and Y4} (Month is valid, Day is valid and Year is invalid)
I71 = {M1 and D4 and Y3} (Month is valid, Day is valid and Year is invalid)
I72 = {M1 and D4 and Y4} (Month is valid, Day is valid and Year is invalid)
I73 = {M2 and D4 and Y3} (Month is valid, Day is valid and Year is invalid)
I74 = {M2 and D4 and Y4} (Month is valid, Day is valid and Year is invalid)
376 Object-Oriented Software Engineering
I75 = {M3 and D4 and Y3} (Month is valid, Day is valid and Year is invalid)
I76 = {M3 and D4 and Y4} (Month is valid, Day is valid and Year is invalid)
I77 = {M4 and D5 and Y1} (Month is invalid, Day is invalid and Year is valid)
I78 = {M4 and D5 and Y2} (Month is invalid, Day is invalid and Year is valid)
I79 = {M4 and D6 and Y1} (Month is invalid, Day is invalid and Year is valid)
I80 = {M4 and D6 and Y2} (Month is invalid, Day is invalid and Year is valid)
I81 = {M5 and D5 and Y1} (Month is invalid, Day is invalid and Year is valid)
I82 = {M5 and D5 and Y2} (Month is invalid, Day is invalid and Year is valid)
I83 = {M5 and D6 and Y1} (Month is invalid, Day is invalid and Year is valid)
I84 = {M5 and D6 and Y2} (Month is invalid, Day is invalid and Year is valid)
I85 = {M4 and D1 and Y3} (Month is invalid, Day is valid and Year is invalid)
I86 = {M4 and D1 and Y4} (Month is invalid, Day is valid and Year is invalid)
I87 = {M4 and D2 and Y3} (Month is invalid, Day is valid and Year is invalid)
I88 = {M4 and D2 and Y4} (Month is invalid, Day is valid and Year is invalid)
I89 = {M4 and D3 and Y3} (Month is invalid, Day is valid and Year is invalid)
I90 = {M4 and D3 and Y4} (Month is invalid, Day is valid and Year is invalid)
I91 = {M4 and D4 and Y3} (Month is invalid, Day is valid and Year is invalid)
I92 = {M4 and D4 and Y4} (Month is invalid, Day is valid and Year is invalid)
I93 = {M5 and D1 and Y3} (Month is invalid, Day is valid and Year is invalid)
I94 = {M5 and D1 and Y4} (Month is invalid, Day is valid and Year is invalid)
I95 = {M5 and D2 and Y3} (Month is invalid, Day is valid and Year is invalid)
I96 = {M5 and D2 and Y4} (Month is invalid, Day is valid and Year is invalid)
I97 = {M5 and D3 and Y3} (Month is invalid, Day is valid and Year is invalid)
I98 = {M5 and D3 and Y4} (Month is invalid, Day is valid and Year is invalid)
I99 = {M5 and D4 and Y3} (Month is invalid, Day is valid and Year is invalid)
I100 = {M5 and D4 and Y4} (Month is invalid, Day is valid and Year is invalid)
I101 = {M1 and D5 and Y3} (Month is valid, Day is invalid and Year is invalid)
I102 = {M1 and D5 and Y4} (Month is valid, Day is invalid and Year is invalid)
I103 = {M2 and D5 and Y3} (Month is valid, Day is invalid and Year is invalid)
I104 = {M2 and D5 and Y4} (Month is valid, Day is invalid and Year is invalid)
I105 = {M3 and D5 and Y3} (Month is valid, Day is invalid and Year is invalid)
I106 = {M3 and D5 and Y4} (Month is valid, Day is invalid and Year is invalid)
I107 = {M1 and D6 and Y3} (Month is valid, Day is invalid and Year is invalid)
I108 = {M1 and D6 and Y4} (Month is valid, Day is invalid and Year is invalid)
I109 = {M2 and D6 and Y3} (Month is valid, Day is invalid and Year is invalid)
I110 = {M2 and D6 and Y4} (Month is valid, Day is invalid and Year is invalid)
I111 = {M3 and D6 and Y3} (Month is valid, Day is invalid and Year is invalid)
I112 = {M3 and D6 and Y4} (Month is valid, Day is invalid and Year is invalid)
I113 = {M4 and D5 and Y3} (All inputs are invalid)
Software Testing 377
I114 = {M4 and D5 and Y4} (All inputs are invalid)
I115 = {M4 and D6 and Y3} (All inputs are invalid)
I116 = {M4 and D6 and Y4} (All inputs are invalid)
I117 = {M5 and D5 and Y3} (All inputs are invalid)
I118 = {M5 and D5 and Y4} (All inputs are invalid)
I119 = {M5 and D6 and Y3} (All inputs are invalid)
I120 = {M5 and D6 and Y4} (All inputs are invalid)
The test cases generated on the basis of input domain are given in Table 9.23.
(Contd.)
378 Object-Oriented Software Engineering
(Contd.)
Software Testing 379
(Contd.)
380 Object-Oriented Software Engineering
There are two types of decision tables. The first type is called the limited entry decision
table where input values represent only the true and false condition as shown in Table 9.25.
Software Testing 381
Table 9.25 Limited entry decision table
Condition stub Condition entry
c1 T F F F F
c2 - T F F F
c3 - - T F F
- - - T F
a1 X X
a2 X X
a3 X X
Every column of the decision table represents a rule and generates a test case. A ‘-’ in the
condition entry represents a ‘do not care’ condition. An ‘X’ in the action entry represents the
action mentioned in the corresponding action stub. In Table 9.25, if condition c1 is true, then c2,
c3 and c4 become ‘do not care’ conditions and actions a1 and a3 are to be performed.
The second type of decision table is called extended entry decision table. In such a table,
multiple conditions are used instead of true and false conditions. A condition may have many
options instead of only true and false and such options are represented in the extended entry
decision table.
We consider a program which takes a date as an input and checks whether it is a valid date
or not. We prepare the following classes (options) and represent them in the extended entry
decision table as shown in Table 9.26.
I1 = {M1 : Month has 30 days}
I2 = {M2 : Month has 31 days}
I3 = {M3 : Month is February}
I4 = {M4 : Month <1}
I5 = {M5 : Month > 12}
I6 = {D1 : 1 Day 28}
I7 = {D2 : Day = 29}
I8 = {D3 : Day = 30}
I9 = {D4 : Day = 31}
I10 = {D5 : Day < 1}
I11 = {D6 : Day > 31}
I12 = {Y1 : 1900 Year 2058 and is a common year}
I13 = {Y2 : 1900 Year 2058 and is a leap year}
I14 = {Y3 : Year < 1900}
I15 = {Y4 : Year > 2058}
In the decision table, various combinations of conditions are considered and that may
sometimes result into an impossible action. In such a situation, we may incorporate an additional
action ‘impossible condition’ in the action stub. We may change the design of equivalence classes
to reduce the impossible conditions.
Table 9.26 Decision table of date program
382
Test case 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
c1 : Months in M1 M1 M1 M1 M1 M1 M1 M1 M1 M1 M1 M1 M1 M1 M1 M1 M1 M1 M2 M2
c2 : Days in D1 D1 D1 D1 D2 D2 D2 D2 D3 D3 D3 D3 D4 D4 D4 D4 D5 D6 D1 D1
c3 : Years in Y1 Y2 Y3 Y4 Y1 Y2 Y3 Y4 Y1 Y2 Y3 Y4 Y1 Y2 Y3 Y4 - - Y1 Y2
Rule count 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 4 4 1 1
a1 : Invalid date X X
a2 : Valid date X X X X X X X X
a3 : Input out of range X X X X X X X X X X
Test case 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
c1 : Months in M2 M2 M2 M2 M2 M2 M2 M2 M2 M2 M2 M2 M2 M2 M2 M2 M3
Object-Oriented Software Engineering
c2 : Days in D1 D1 D2 D2 D2 D2 D3 D3 D3 D3 D4 D4 D4 D4 D5 D6 D1
c3 : Years in Y3 Y4 Y1 Y2 Y3 Y4 Y1 Y2 Y3 Y4 Y1 Y2 Y3 Y4 - - Y1
Rule count 1 1 1 1 1 1 1 1 1 1 1 1 1 1 4 4 1
a1 : Invalid date
a2 : Valid date X X X X X X X
a3 : Input out of range X X X X X X X X X X
Test case 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56
c1 : Months in M3 M3 M3 M3 M3 M3 M3 M3 M3 M3 M3 M3 M3 M3 M3 M3 M3 M4 M5
c2 : Days in D1 D1 D1 D2 D2 D2 D2 D3 D3 D3 D3 D4 D4 D4 D4 D5 D6 - -
c3 : Years in Y2 Y3 Y4 Y1 Y2 Y3 Y4 Y1 Y2 Y3 Y4 Y1 Y2 Y3 Y4 - - - -
Rule count 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 24 24
a1 : Invalid date X X X X X
a2 : Valid date X X
a3 : Input out of range X X X X X X X X X X X X
Software Testing 383
Decision tables are used in situations where an output is dependent on many input conditions.
Complex relationships can also be easily represented in such tables. Every column may generate
a test case. The test cases of decision Table 9.26 are given in Table 9.27.
Decision tables are effectively applicable to small-size programs. As the size increases,
handling becomes difficult and time consuming. We can easily apply the decision table at the
unit level. System testing and integration testing do not find its applicability in any reasonable-
size program.
EXAMPLE 9.7 Consider a program to multiply and divide two numbers. The inputs may be
two valid integers (say a and b) in the range of [0, 100]. Develop the decision table and generate
test cases.
Solution The decision table is given in Table 9.28 and the test cases are given in Table 9.29.
Software Testing 385
Table 9.28 Decision table for a program to multiply and divide two numbers
Input in valid range? F T T T T
a = 0? - T T F F
b = 0? - T F T F
Input values out of range X
Valid output X X
Output undefined X
Divide by zero error X
Table 9.29 shows the test cases generated from the above decision table.
Table 9.29 Test cases for decision table shown in Table 9.28
Test case a b Expected output
1 50 –1 Input values are out of range
2 0 0 Output undefined
3 0 50 0 0
4 30 0 Divide by zero error
5 50 50 2500 1
The program graph provides the graphical view of the program and may become the
foundation of many testing techniques. The fundamental constructs of the program graph are
given in Figure 9.7.
386 Object-Oriented Software Engineering
#include<stdio.h>
#include<conio.h>
1 void main()
2 {
3 int num;
4 clrscr() ;
5 cout<<"Enter number" ;
6 cin>>num ;
Figure 9.8 (Contd.)
Software Testing 387
7 if(num%2==0)
8 {
9 cout<<"Number is even";
10 }
11 else
12 {
13 cout<<"Number is odd";
14 }
15 getch();
16 }
Figure 9.8 Program to determine whether a number is even or odd.
A path in a graph is a sequence of adjacent nodes where nodes in sequence share a common
edge or sequence of adjacent pair of edges where edges in sequence share a common node. It is
clear from the program graph that there are two paths in the graph.
These paths are 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 15, 16 and 1, 2, 3, 4, 5, 6, 7, 11, 12, 13, 14, 15, 16.
Every program graph has one source node and one destination node. In the program graph given
in Figure 9.9, nodes 1 to 6 are in sequence, node 7 has two outgoing edges (predicate node) and
node 15 is a junction node.
A program graph can be converted into a DD program graph. There are many nodes in
the program graph which are in a sequence like nodes 1 to 6 of the program graph given in
Figure 9.9. When we enter into the sequence through the first node, we can exit only from the
last node of the sequence. In the DD path graph, all nodes which are in a sequence are combined
and represented by a single node. The DD path graph is a directed graph in which nodes are the
388 Object-Oriented Software Engineering
sequence of statements and edges are the control flow amongst the nodes. All DD path graphs have
a source node and a destination node similar to the program graph. A mapping table is prepared
to match the nodes of the DD path graph to the corresponding nodes of the program graph. All
sequential nodes are combined into a single node which reduces the size of the DD path graph.
Mapping table of the program graph given in Figure 9.9 is presented in Table 9.30.
The corresponding DD path graph is given in Figure 9.10. There are two paths, namely, S,
N1, N2, N3, N5, D and S, N1, N2, N4, N5, D. Paths in the program are identified from the DD
path graph easily. We may like to see the behaviour of the program when every identified path
is executed. Hence, we may design test cases in such a way that at least every identified path is
executed during testing.
Cyclomatic complexity also provides some insight into the complexity of a module.
McCabe (1976) proposed an upper limit of cyclomatic complexity to 10 with significant
supporting evidence. We may go up to 15 in today’s scenario of new programming languages,
availability of CASE tools, effective validation and verification techniques, and implementation
of software engineering principles and practices. If the limit further exceeds, it is advisable to
redesign the module and maintain the cyclomatic complexity within prescribed limits.
The program graph may generate a few paths which are impossible in practice. When we
give inputs, some paths may not be possible to traverse due to logic of the program. Hence, some
paths are impossible to create and traverse and cannot be implemented. Path testing ensures
100% statement and branch coverage and guarantees a reasonable level of confidence about the
correctness of the program.
#include<stdio.h>
#include<conio.h>
1 void main()
2 {
3 int a,b,c,validInput=0,d;
4 clrscr();
5 cout<<"Enter values of a, b & c:\n";
6 cin>>a>>b>>c;
7 if((a>=0)&&(a<=100)&&(b>=0)&&(b<=100)&&(c>=0)&&(c<=100)){
8 validInput=1;
9 if(a==0){
10 validInput=-1;
11 }
12 }
13 if(validInput==1){
14 d=b*b-4*a*c;
15 if(d==0){
16 cout<<"Equal roots";
17 }
18 else if(d>0){
19 cout<<"Real roots";
20 }
21 else{
22 cout<<"Imaginary roots";
23 }
24 }
25 else if(validInput==-1){
26 cout<<"Not quadratic";
27 }
28 else {
29 cout<<"The inputs are out of range";
30 }
31 getch();
32 }
392 Object-Oriented Software Engineering
The activity diagram for finding the roots of a quadratic equation is given in Figure 9.11.
Figure 9.11 Activity diagram for finding the roots of a quadratic equation.
Cyclomatic complexity = 22 – 17 + 2 = 7
Software Testing 393
The test cases for independent paths are given in Table 9.32.
Queue
x: integer
front: integer
rear: integer
Queue( )
Insert(x)
Remove( )
Figure 9.12 Structure of the class ‘queue’.
We identify all pre- and postconditions for every operation of class ‘queue’. There are three
operations and their pre- and postconditions are given as:
(i) Operation Queue: The purpose of this operation is to create a queue
Queue::queue( )
(a) Pre = true
(b) Post: front = 0, rear = 0
(ii) Operation Insert(x): This operation inserts an item x into the queue.
Queue::insert(x)
(a) Pre: rear < MAX
(b) Post: rear = rear + 1
(iii) Operation Remove( ): This operation removes an item from the front side of the queue.
Queue::remove( )
(a) Pre: front > 0
(b) Post: front = front + 1
We establish logical relationships between identified pre- and postconditions for insert(x) and
remove() operations.
Insert(x):
1. (precondition: rear < MAX; postcondition: rear = rear + 1)
2. (precondition: not (rear < MAX); postcondition: exception)
Similarly for remove( ) operation, the following logical relationships are established:
3. (precondition: front > 0; postcondition: front = front + 1)
4. (precondition: not (front > 0); postcondition: exception)
Test cases are generated for every established logical relationship of pre- and postconditions.
Test cases for insert(x) and remove( ) operations are given in Table 9.33.
We should not confuse with the start state and end state of the statechart diagram. a and w
are additional states and are represented explicitly in the statechart diagram. We consider an
example of a class ‘queue’ with two operations—insert and remove. The queue is based on
the principle of FIFO (first in first out) and there are three states: empty, holding and full. In
addition to these three states, two additional states a and w are also used. There are four events,
namely, new, insert, remove and destroy with the following objectives:
New: Creates an empty queue.
Insert: Inserts an element in the queue, if space is available.
Remove: Removes an element from the queue, if it is available.
Destroy: Destroys the queue after the completion of its requirement, i.e. object of the
queue class is destroyed.
We may draw the statechart diagram of the queue class as given in Figure 9.13.
The statechart diagram gives the graphical view of the behaviour of the system. All
transitions are shown along with self-loop type transitions. In the above statechart diagram, the
holding state has two self-loops for the following purposes:
(i) When [rear < MAX – 1], we insert an element x and the same state is maintained.
(ii) When [front > 1], we remove an element, the same state is maintained.
If the number of states increases, it becomes difficult to draw the statechart diagram and keep
track of various transitions. In practice, the number of states is very large (more than 100 also)
and it may not be possible to draw a statechart diagram. Another option is to represent the
statechart diagram’s information in tabular form and this table is known as state transition
table. The row of the table represents the present state and the column represents the resultant
state. The state transition table of ‘queue’ class is given in Table 9.34. The state transition table
incorporates every information of the statechart diagram such as transitions, events and actions,
and may become the basis to design the test cases.
new √
insert(x)
remove()
destroy
Empty new
insert(x)
remove()
destroy √
Holding new
insert(x) √ √
remove() √ √
destroy √
Full new
insert(x)
remove() √
destroy √
These test cases are systematic and cover every functionality of the ‘queue’ class. The state-
based testing is simple, effective and systematically generates a good number of test cases.
time and resource constraints. We attempt to reduce the size on the basis of some techniques.
However, if we execute all test cases and do not find any fault in the program, there are the
following possibilities:
(i) Test suite is effective, but there are no faults in the program.
(ii) Test suite is not effective, although there are faults in the program.
In both possibilities, we could not make our program fail, although reasons of non-failure of the
program are different. In the first case, the quality of the program is good and there are no faults
in the program. However, in the second case, there are faults in the program but test cases are
not able to find them. Hence, mutation testing helps us to know the effectiveness of an existing
test suite with reasonable level of accuracy.
#include<iostream.h>
#include<conio.h>
1 class smallest
2 {
3 private:
4 int a,b,c;
5 public:
6 void getdata()
7 {
8 cout<<"Enter first number: ";
9 cin>>a;
10 cout<<"\nEnter second number: ";
11 cin>>b;
12 cout<<"\nEnter third number: ";
13 cin>>c;
14 }
15 void compute();
16 };
17 void smallest::compute()
18 {
19 if(a<b)
20 {
21 if(a<c)
22 {
23 cout<<"\nThe smallest number is:"<<a;
24 }
25 Else
26 {
27 cout<<"\nThe smallest number is:"<<c;
28 }
29 }
30 Else
31 {
32 if(c<b)
33 {
34 cout<<"\nThe smallest number is:"<<c;
35 }
36 Else
37 {
38 cout<<"\nThe smallest number is:"<<b;
39 }
40 }
41 }
42 void main()
43 {
44 clrscr();
45 smallest s;
46 [Link]();
47 [Link]();
48 getch();
49 }
The mutant M1 is created by replacing the operator ‘<’ of line number 19 by the operator ‘=’. The
mutant M2 is created by replacing the operator ‘<’ of line number 32 by the operator ‘>’. These
400 Object-Oriented Software Engineering
changes are simple and both mutants are different than the original program. Both mutants are
also different than each other but are syntactically correct. The mutants are known as first-order
mutants. We may also get second-order mutants by making two changes in the program and
third-order mutants by making three changes and so on. The second-order and above mutants
are called higher-order mutants. However, in practice, we generally use only the first-order
mutants in order to simplify the process of mutation. The second-order mutants can be created
by making two changes in the program as shown in Figure 9.17.
The total number of mutants is equal to the number of killed mutants plus the number of live
mutants. A mutation score range is from 0 to 1. The higher value of a mutation score shows the
effectiveness of the test suite. If the mutation score is 0, it indicates that the test suite is not able
to detect any introduced fault in mutants and is useless for the program. The live mutants are
important and should be studied thoroughly. Special test cases should be designed to kill live
mutants. The new test cases which are able to kill live mutants should be added to the original
test suite to enhance its capability. The mutation testing not only assesses the capability of the
test suite but also enhances the capability by adding new test cases. Some of the popular tools
are insure++, Jester for Java, nester for C++, MuJava tool, Mothra, etc.
We consider the program given in Figure 9.14 to find the smallest of three numbers.
Table 9.36 shows the test suite available to test the program.
Table 9.36 Test suite to test the program given in Figure 9.14
S. No. A B C Expected output
1 3 1 5 1
2 6 2 8 2
3 4 5 7 4
4 8 6 3 3
5 9 10 6 6
The actual output of all mutants with existing test suite is given in Table 9.38.
The existing test suite kills five mutants (M1 to M5), but fails to kill mutant M6. Hence, a
mutation score is calculated as given below:
Number of mutants killed
Mutation score =
Total number of mutants
5
=
6
= 0.83
Effectiveness of a test suite is directly related to the mutation score. Mutant M6 is live here and
an additional test case is to be written to kill this mutant. The additional test case is created to
kill this mutant M6 and is given in Table 9.39.
When we execute this test case, we get the observed behaviour of the program given in Table 9.40.
This additional test case is very important and must be added to the given test suite. Therefore,
the revised test suite is given as in Table 9.41.
Software Testing 403
Table 9.41 Revised test suite
S. No. A B C Expected output
1 3 1 5 1
2 6 2 8 2
3 4 5 7 4
4 8 6 3 3
5 9 10 6 6
6 6 4 5 4
inspections and walkthroughs are easily applicable and may find a good number of faults. State-
based testing, path testing, class testing, boundary value analysis, equivalence class and decision
table-based testing techniques are also applicable.
Review Questions
1. What is software testing? Discuss issues, limitations, practices and future of software
testing.
2. “Testing is not related to only one phase of software development life cycle”. Comment
on the correctness of this statement.
3. Differentiate between verification and validation. Which one is more important and
why?
4. Which is the most popular verification technique? Explain with suitable examples.
5. Write short notes on the following verification techniques:
(a) Peer reviews
(b) Walkthroughs
(c) Inspections
6. Design an SRS document verification checklist. Highlight some important issues which
such a checklist must address.
7. What is a checklist? Discuss its significance and role in software testing.
8. Differentiate between walkthroughs and inspections. List the advantages and disadvantages
of both techniques.
9. Design checklists for OOA document and OOD document. Both checklists should cover
important issues of both documents.
10. Establish the relationship between verification, validation and testing along with suitable
examples.
11. What is functional testing? Discuss any one technique with the help of an example.
12. What is boundary value analysis? What are its extensions? List the advantages and
limitations of each extension.
13. Consider a program that determines the previous date and the next date. Its inputs are a
triple of day, month and year with its values in the following range:
1 month 12
1 day 31
1947 year 2011
The possible outputs are “next date”, “previous date” or “invalid input”. Design boundary
value analysis test cases, robust test cases, worst test cases and robust worst test cases.
408 Object-Oriented Software Engineering
14. Consider a program that calculates median of three numbers. Its input is a triple of
positive integers (say a, b and c) and values are from the interval [1, 1000]. Generate
boundary value and robust test cases.
15. Describe the equivalence class testing technique. How is it different from boundary
value analysis?
16. What is decision table-based testing? What is the role of a rule count? Discuss the
concept with an example.
17. Consider a program to sort a list in ascending order. Write test cases using equivalence
class testing and decision table-based testing.
18. What are the limitations of boundary value analysis? Highlight the situations in which
it is not effective.
19. Consider a program that counts the number of digits in a number. The range of input is
given as [1, 1000]. Design the boundary value analysis and equivalence class test cases.
20. What is structural testing? How is it different from functional testing?
21. What is path testing? How can we make it more effective and useful?
22. Show that a very high level of statement coverage does not guarantee a defect-free
program. Give an example to explain the concept.
23. What is mutation testing? What is the significance of mutation score? Why are higher-
order mutants not preferred?
24. Why is mutation testing becoming popular? List some significant advantages and
limitations.
25. What is a program graph? How can it be used in path testing?
26. Define the following:
(a) Program graph
(b) DD path graph
(c) Mapping table
(d) Independent paths
27. What is class testing? Why should unspecified behaviour not be implemented?
28. What is state-based testing? What are alpha and omega states? List the advantages and
limitations of the state-based testing.
29. What are levels of testing? Which level is most popular and why?
30. Explain the concept of flattening of classes. How can it help in unit testing?
31. Discuss the importance of software testing tools. List some static, dynamic and process
management tools.
32. Differentiate between static and dynamic testing tools. Which one is more effective and
why?
33. “Some non-functional requirements cannot be tested without using a software testing
tools”. Comment on this statement and justify with an example.
Software Testing 409
34. Differentiate between black box testing and white box testing. Consider a program to
find the smallest number amongst three numbers. Generate test cases using one of the
testing techniques.
35. Write short notes on:
(a) Software testing tools
(b) State-based testing
(c) Class testing
Further Reading
Fagan shows that by using inspection, the cost of errors may be reduced significantly in initial
phases of software development:
Fagan, M.E., Design and code inspections to reduce errors in program development. IBM Systems
Journal, 15(3): 182–211, 1976.
Strauss et al. provide a comprehensive guide to software inspections method that may reduce
program defects in the early phases of software design and development:
Strauss, S.H., Susan, H., and Ebenau, Robert G., Software Inspection Process. New York:
McGraw-Hill, 1994.
Yourdon’s book may provide a useful guidance to practitioners and programmers on group
walkthroughs:
Yourdon, E., Structured Walkthroughs. Englewood Cliffs, NJ: Prentice-Hall, 1989.
The below book is resource for pre-1981 literature and contains a huge bibliography up to and
including 1981:
Miller, E.F. and Howden, W.E., Tutorial: Software Testing and Validation Techniques.
New York: IEEE Computer Society, 1981.
A hands-on guide to the black box testing technique:
Beizer, B., Black-Box Testing: Techniques for Functional Testing of Software and Systems.
New York: John Wiley & Sons, 1995.
An introductory book on software testing with a special focus on functions testing is:
Jorgensen, P.C., Software Testing: A Craftsman Approach, 3rd ed. New York: Auerbach
Publications, 2007.
A useful guide for designing test cases for object-oriented applications. This book provides
comprehensive and detailed coverage of techniques to develop testable models from unified
modelling language and state machines:
Binder, R.V., Testing Object Oriented Systems: Models, Patterns and Tools. Reading,
MA: Addison-Wesley, 1999.