You are on page 1of 66

Chapter Six

Coding
1
Programming Practice
• The goal of the coding or programming activity is to
implement the design in the best possible manner.

• Affects testing and maintenance


• Good programming (producing correct and simple
programs) is a practice independent of the target
programming language, although well-structured
programming languages make the programmer's job

simpler. 2
• As testing and maintenance costs are high,
aim of coding activity should be to write
code that reduces them
• Hence, goal should not be to reduce coding
cost, but testing and maintained cost, i.e.
make the job of tester and maintainer easier

3
• Code is read a lot more
• Coders themselves read the code many times for
debugging, extending etc
• Maintainers spend a lot of effort reading and
understanding code
• Other developers read code when they add to existing
code
• Hence, code should be written so it is easy to
understand and read, not easy to write

4
Common Coding Errors/ defects/
bugs
• Memory Leaks
• A memory leak is a situation where the memory is
allocated to the program which is not freed
subsequently.
• languages which do not have automatic garbage
collection
• They have little impact in short programs but can have
catastrophic effect on long running systems.
• A software system with memory leaks keeps
consuming memory, till at some point of time the
program may come to an exceptional halt because of5
the lack of free memory.
void memLeak( ) {
int *data = new int; *data = 15;
}
the ―*data‖ pointer is never deleted – which
means that the data it references is never
deallocated, and memory is wasted.

6
• Freeing an Already Freed Resource
• In general, in programs, resources are first
allocated and then freed.

• For example, memory is first allocated and then


deallocated.
• This error occurs when the programmer tries to free
the already freed resource.

• The impact of this common error can be


catastrophic. 7
• The impact of this error can be more severe
if we have some malloc statement between
the two free statements—there is a chance
that the first freed location is now allocated
to the new variable and the subsequent free
will deallocate it!
8
NULL Dereferencing
• This error occurs when we try to access the
contents of a location that points to NULL.
• This is a commonly occurring error which can
bring a software system down.
• It is also difficult to detect as it the NULL
dereferencing may occur only in some paths
and only under certain situations.

9
10
Lack of Unique
• For example Addresses
in the string concatenation
function, we expect source and destination
addresses to be different.

• If this is not the case, as is the situation in


the code segment below, it can lead to
runtime errors.

• strcat (src , destn ); 11


Synchronization Errors
• Possible when there are multiple threads which are
accessing some common resources, in a parallel program
• three categories of synchronization errors: deadlocks, race
condition, Inconsistent synchronization
• Deadlock example:
Thread 1: synchronized
(A){ synchronized (B){ }
}
Thread 2:
synchronized (B){
synchronized (C){ }
}
Thread 3:
synchronized (C){

synchronized (A){ } 12
}
• Race condition occurs when two threads
access same resource and result depends on
the order of the execution

• a mix of locked and unlocked accesses to


some shared variables, particularly if the
access involves updates.
13
Array Index Out of Bounds
• Array index often goes out of bounds,
leading to exceptions.

• Care needs to be taken to see that the array


index values are not negative and do not
exceed their bounds.

14
Arithmetic exceptions
• These include errors like divide by zero and
floating point exceptions.

• The result of these may vary from getting


unexpected results to termination of the
program.

15
Off by One
• This is one of the most common errors
which can be caused in many ways.

• For example, starting at 1 when we should


start at 0 or vice versa, writing <= N instead
of < N or vice versa, and so on.

16
Enumerated data types
• Overflow and underflow errors can easily
occur when working with enumerated types,
and care should be taken when assuming the
values of enumerated data types.

17
• An example of such an error is:

18
Buffer overflow
• Though buffer overflow is also a frequent
cause of software failures, in to days world
its main impact is that it is a security flaw
that can be exploited by a malicious user for
executing arbitrary code.

19
20
Some Programming Practices
• Control Constructs: it is desirable that as
much as possible single-entry, single-exit
constructs be used.

• It is also desirable to use a few standard


control constructs rather than using a wide
variety of constructs
21
• Gotos: Gotos should be used sparingly and
in a disciplined manner.

• Only when the alternative to using gotos is


more complex should the gotos be used.
• If goto is a must forward transfers (or a jump to
a later statement) is more acceptable than a

backward jump. 34
• Information Hiding: information hiding
should be supported where possible.

• Only the access functions for the data


structures should be made visible while
hiding the data structure behind these
functions.
23
• User-Defined Types: should be exploited
where applicable.

• Nesting: If nesting of if-then-else constructs


becomes too deep, then the logic become
harder to understand.

• Where possible, deep nesting should be avoided


24
• Module Size: There can be no hard-and-
fast rule about module sizes; the guiding
principle should be cohesion and coupling.

25
• Module Interface: A module with a
complex interface should be carefully
examined.

• As a rule of thumb, any module whose


interface has more than five parameters
should be carefully examined and broken
into multiple modules with a simpler
interface if possible 38
• Side Effects: When a module is invoked, it
sometimes has side effects of modifying the
program state beyond the modification of
parameters listed in the module interface
definition.

• For example, modifying global variables.


• Such side effects should be avoided where
possible, and if a module has side effects, they
39
should be properly documented.
• Robustness: A program is robust if it does
something planned even for exceptional
conditions.
• incorrect input, the incorrect value of some
variable, and overflow.

• If such situations do arise, the program


should not just ―crash‖ or ―core dump‖; it
should produce some meaningful message
40
and exit gracefully.
• Switch Case with Default: If there is no
default case in a ―switch‖ statement, the
behavior can be unpredictable.

• Such a practice can result in a bug like


NULL dereference, memory leak, as well as
other types of serious bugs. It is a good

practice to always include a default case. 41


• Empty Catch Block: An exception is
caught, but if there is no action, it may
represent a scenario where some of the
operations to be done are not performed.
• Whenever exceptions are caught, it is a good
practice to take some default action, even if it is
just printing an error message.
30
• Empty if, while Statement: A condition is
checked but nothing is done based on the
check. This often occurs due to some
mistake and should be caught.

31
• Read Return to Be Checked: Often the
return value from reads is not checked,
assuming that the read returns the desired
values.

• Sometimes the result from a read can be


different from what is expected, and this

can cause failures later. 44


• Return from Finally Block: One should
not return from finally block, as it can
create false beliefs.

33
• a value is returned both in exception and
non-exception scenarios.
• at the caller site, the user will not be able to
distinguish between the two.

34
• when we have a return from try block. In
this case, if there is a return in finally also,
then the value from finally is returned
instead of the value from try.

35
• Correlated Parameters: Often there is an
implicit correlation between the parameters.

• If the correlation does not hold, we can run


into a serious problem like buffer overflow
(illustrated in the code fragment below).
• Hence, it is a good practice to validate this
correlation rather than assuming that it holds.

36
• Trusted Data Sources: Counter checks
should be made before accessing the input
data, particularly if the input data is being
provided by the user or is being obtained
over the network.
• We should put some checks, like parity checks,
hashes, etc., to ensure the validity of the
incoming data.

37
• Give Importance to Exceptions: To make
a software system more reliable, a
programmer should consider all possibilities
and write suitable exception handlers to
prevent failures or loss when such situations
occur.
38
Chapter Seven

Testing

39
Testing Fundamentals

• Error, Fault, and Failure: the IEEE


definitions for these terms
• The term error is used in two different ways.
• It refers to the discrepancy between a computed,
observed, or measured value and the true, specified,
or theoretically correct value.
• Error is also used to refer to human action that
results in software containing a defect or fault. This
definition is quite general and encompasses all the
phases.

40
• Fault is a condition that causes a system to fail
in performing its required function.
• A fault is the basic reason for software malfunction
and is synonymous with the commonly used term
bug.
• Failure is the inability of a system or
component to perform a required function
according to its specifications.
• A software failure occurs if the behavior of the
software is different from the specified behavior.
• A failure is produced only when there is a fault in
the system.
41
• Presence of a fault does not guarantee a
failure.
• In other words, faults have the potential to
cause failures and their presence is a
necessary but not a sufficient condition for
failure to occur.
• Note that the definition does not imply that
a failure must be observed.
• It is possible that a failure may occur but
not be detected.
42
• What is called a "failure" is dependent on
the project, and its exact definition is often
left to the tester or project manager.
• For example,
• is a misplaced line in the output a failure or
not? Clearly, it depends on the project; some
will consider it a failure and others will not.

43
• Take another example.
• If the output is not produced within a given
time period, is it a failure or not?
• For a real-time system this may be viewed as a
failure, but for an operating system it may not
be viewed as a failure.

44
• Presence of an error (in the state) implies
that a failure must have occurred, and the
observance of a failure implies that a fault
must be present in the system.
• However, the presence of a fault does not
imply that a failure must occur.
• The presence of a fault in a system only
implies that the fault has a potential to
cause a failure to occur

45
• Whether a fault actually manifests itself in a
certain time duration depends on many factors.
• This means that if we observe the behavior of a
system for some time duration and we do not
observe any errors, we cannot say anything about
the presence or absence of faults in the system.
• If, on the other hand, we observe some failure in
this duration, we can say that there are some faults
in the system.

46
Test Cases and Test Criteria

• Having test cases that are good at revealing


the presence of faults is central to successful
testing.
• The reason for this is that if there is a fault
in a program, the program can still provide
the expected behavior for many inputs.
• Hence, it is fair to say that testing is as good as
its test cases.

47
• Ideally, we would like to determine a set of
test cases such that successful execution of
all of them implies that there are no errors
in the program.
• This ideal goal cannot usually be achieved
due to practical and theoretical constraints.
• Each test case costs money, as effort is
needed to generate the test case, machine
time is needed to execute the program for
that test case, and more effort is needed to
evaluate the results.

48
• Therefore, we would also like to minimize
the number of test cases needed to detect
errors.
• These are the two fundamental goals of a
practical testing activity—maximize the
number of errors detected and minimize the
number of test cases (i.e., minimize the
cost).

49
Black-Box Testing

• Also called functional or behavioral testing.

• Test cases are decided solely on the basis of the


requirements or specifications of the program or module

• the internals of the module or the program are not


considered for selection of test cases.

• the basis for deciding test cases in functional testing is the


requirements or specifications of the system or module

50
• There are no formal rules for designing test
cases for functional testing.

• But there are a number of techniques or


heuristics that can be used to select test
cases that have been found to be very
successful in detecting errors.

51
Equivalence Class Partitioning

• Divide the input domain into a set of


equivalence classes, so that if the program
works correctly for a value then it will work
correctly for all the other values in that
class.

52
• Example-1, the specifications of a module
that determines the absolute value for
integers specify one behavior for positive
integers and another for negative integers.
• In this case, we will form two equivalence
classes—one consisting of positive integers and
the other consisting of negative integers.
53
• Example-2 : User Authentication

Input/ Output Valid Equivalence Invalid Equivalence


Event Classes Classes
Password Input Non empty, less than Empty, more than 32
32 characters characters

Username Input Non empty, less than Empty, more than 32


32 characters characters

54
• Example: consider a program that takes two
inputs—a string s of length up to N and an
integer n. The program is to determine the
top n highest occurring characters in s

55
Input Valid Equivalence Classes Invalid Equivalence
Classes

s EQ1: Contains numbers IEQ1: non- ASCII


EQ2: Contains lower case letters characters
EQ3: Contains special characters IEQ2: String length>N
EQ4: String length between 0-N

n EQ6: Integer in valid range IEQ3: Integer out of


range

56
Boundary Value Analysis

• Test cases that have values on the


boundaries of equivalence classes are likely
to be "high-yield" test cases, and selecting
such test cases is the aim of the boundary
value analysis
• In case of ranges, for boundary value
analysis it is useful to select the boundary
elements of the range and an invalid value
just beyond the two ends

57
• Example
• if the range is 0.0 < x < 1.0, then the test cases
are 0.0, 1.0 (valid inputs), and -0.1, and 1.1 (for
invalid inputs).

• Similarly, if the input is a list, attention


should be focused on the first and last
elements of the list.

58
• Other techniques
• Cause-Effect Graphing
• Pair-wise Testing and
• State-Based Testing are also mechanisms by
which we perform black box testing.

59
White-Box Testing

• Is also called structural testing


• It is concerned with testing the
implementation of the program.
• The intent of this testing is not to exercise
all the different input or output conditions
but to exercise the different programming
structures and data structures used in the
program.

60
Control Flow-Based Criteria

• based on the control flow of the program.


• statement coverage
• which requires that each statement of the
program be executed at least once during
testing.
• not very strong, and can leave errors
undetected.

61
62
• branch coverage
• requires that each decision in the program be
evaluated to true and false values at least once
during testing.
• Other techniques of white-box testing
• data flow-based testing, and mutation testing

63
Test Case Template

• IEEE Standard 610 (1990) defines test case as follows:


• (1) A set of test inputs, execution conditions, and expected
results developed for a particular objective, such as to
exercise a particular program path or to verify compliance
with a specific requirement.
• (2) (IEEE Std 829-1983) Documentation specifying inputs,
predicted results, and a set of execution conditions for a
test item.

64
65
The End

66

You might also like