Inspection and Testing
Diomidis Spinellis
Department of Management Science and Technology
Athens University of Economics and Business
Athens, Greece
dds@aueb.gr
Example: Processor Testing
Intel 8088 processor register test routine from IBM's 1981 PC BIOS.
The carry flag is used as the loop index.
Static Verification
Examples:
Characteristics:
- Detection of common errors
- Various levels of inference
- False positives and negatives
Identified Issues
- Possible bugs
- Portability problems (C/C++)
- Function return values (C/C++)
- Dead code
- Overcomplicated expressions
- Suboptimal code
- Duplicate code
Some FindBugs Issues
(FindBugs reports more than 200 issues.)
- An apparent infinite recursive loop.
- A container is added to itself.
- A volatile reference to an array doesn't treat the array elements as volatile
- Usage of GetResource may be unsafe if class is extended
- Creates an empty jar file entry
- Dubious catching of IllegalMonitorStateException
- Method performs math using floating point precision
- Class implements Cloneable but does not define or use clone method
- clone method does not call super.clone()
- Method might drop exception
- Method might ignore exception
- Method invokes dubious new String(String) constructor; just use the argument
- Method invokes dubious new String() constructor; just use ""
A FindBugs Run
GCC Best Practices
- Compile C/C++ with all warnings enabled (gcc -Wall)
- When warnings are enabled, alse enable optimization (gcc -O)
- Treat warnings as errors (gcc -Werror)
- Compile a debug version of C++ code defining -D_GLIBCXX_DEBUG -D_GLIBCXX_DEBUG_PEDANTIC
- Annotate printf-like functions. Example:
extern void argp_error (__const struct argp_state *__restrict __state,
__const char *__restrict __fmt, ...)
__attribute__ ((__format__ (__printf__, 2, 3)));
(Other formats include scanf, wprintf, wscanf).
C Compilation Example
main(char *argv[])
{
int a, b, c;
a = b;
printf("%g\n", a);
}
Plain compile:
$ gcc t.c
$
Compile with warnings:
$ gcc -O4 -Wall -Werror t.c
cc1: warnings being treated as errors
t.c:9: warning: return-type defaults to `int'
t.c:9: warning: first argument of `main' should be `int'
t.c:9: warning: `main' takes only zero or two arguments
t.c: In function `main':
t.c:13: warning: implicit declaration of function `printf'
t.c:13: warning: double format, different type arg (arg 2)
t.c:10: warning: unused variable `c'
t.c:14: warning: control reaches end of non-void function
t.c:10: warning: `b' might be used uninitialized in this function
Lint Best Practices
- Include a lint pass in your build
- Comment case statements lacking a break with FALLTHROUGH
- Comment uneachable code (exit, longmp) with NOTREACHED
- Comment functions taking format arguments with PRINTFLIKE, SCANFLIKE
- Sparingly use #ifndef lint to silence lint warnings
Tracing Tools
Interface | Tool |
Operating System | strace |
Library | ltrace |
Network | tcpdump |
Resource Snapshot | lsof |
Using Tracing Tools
- Locate bugs without using the source code
- Explain an application's behavior
- Determine undocumented features
- Discover appropriate APIs
- Locate performance bottlenecks
[sl]trace Tips and Tricks
- Trace running processes using the -p flag
- Send output to a file using the -o flag
- Read complete strings using a large argument (e.g. 1024) to -s
- Trace forked processes with the -f flag
Example: System Call Tracing
Which shared libraries is dot loading?
$ strace dot </dev/null 2>&1 | fgrep .so | fgrep -v ENOENT
open("/etc/ld.so.cache", O_RDONLY) = 3
open("/usr/lib/libfreetype.so.6", O_RDONLY) = 3
open("/usr/lib/libpng.so.2", O_RDONLY) = 3
open("/usr/lib/libjpeg.so.62", O_RDONLY) = 3
open("/usr/lib/libz.so.1", O_RDONLY) = 3
open("/lib/libm.so.6", O_RDONLY) = 3
open("/lib/libc.so.6", O_RDONLY) = 3
Example: Library Call Tracing
How does the whoami command obtain its data?
$ ltrace whoami
[...]
geteuid() = 1000
getpwuid(1000, 0x40013678, 0xbffffcac, 0x08048cff, 0x4012ee48) = 0x401310f0
puts("dds"dds
) = 4
exit(0 <unfinished ...>
Unit Testing
- JUnit (http://www.junit.org/) and its friends is the name of the game
- Based on test classes
- Test class contains method annotated
@Before
- Test methods are annotated with
@Test
- Test methods call
assertTrue
- main calls
junit.textui.TestRunner.run(TestClass.class)
JUnit Example
Test Class and Fields
public class RationalTest {
private Rational r12;
private Rational r13;
private Rational r56;
}
Initialization Code
@Before public void setUp() {
r12 = new Rational(1, 2);
r13 = new Rational(1, 3);
r56 = new Rational(5, 6);
}
A Test Method
@Test public void simpleAdd() {
Rational result = r12.add(r13);
assertTrue(result.equals(r56));
}
Run the Class's Test Methods
public static void main (String... args) {
junit.textui.TestRunner.run(RationalTest.class);
}
Textual Regression Testing
- Used for batch oriented applications
- A loop goes over the input files
- Each input file creates a new output file
- Output file compared with correct file
- A "priming" mode allows the creation of the correct files
Example: Testing the Sort Program
#!/bin/sh
FILES=`cd input; echo *`
# Prime test data
if [ "$1" = "-p" ] ; then
for i in $FILES ; do
sort input/$i >old/$i
done
fi
# Compare old with new result
for i in $FILES ; do
sort input/$i >new/$i
if diff old/$i new/$i ; then
echo "OK $i"
else
echo "FAIL $i"
exit 1
fi
done
Test Coverage in C/C++ Code
To investigate test coverage, you can use basic block profiling.
- Compile with gcc -pg -g -fprofile-arcs -ftest-coverage
- Execute program; a file name.bb will be created
- Run gcov -n name.bb
- You will get a report of how many lines were executed
- Numbers less than 100% indicate a lack of coverage
Example:
83.33% of 650 source lines executed in file hilbert.c
Example: Test coverage of Perl's source code versus the number of executed test cases
Further Reading
- Kent Beck and Erich
Gamma.
Test infected: Programmers love writing tests.
Java Report, 3(7):37–50, July 1998.
- David Hovemeyer and
William Pugh.
Finding bugs is easy.
ACM SIGPLAN Notices, 39(12):92–106, December 2004.
OOPSLA 2004 Onward! Track.
- Institute of Electrical and Electronics Engineers.
IEEE Standard for Software Unit Testing.
IEEE, New York, 1987.
IEEE Standard 1008-1987.
- Richard McDougall, Jim
Mauro, and Brendan Gregg.
Solaris
Performance and Tools: DTrace and MDB Techniques for Solaris 10 and
OpenSolaris.
Prentice Hall PTR, Upper Saddle River, 2006.
- Diomidis Spinellis.
I
spy.
IEEE Software, 24(2):16–17, March/April 2007.
(doi:10.1109/MS.2007.43 (http://dx.doi.org/10.1109/MS.2007.43))