Unit Testing Sequential ProgramsSuppose, we want to test the function testme in the following small program contained in the file Struct.java.
package test;
import cute.Cute;
public class Struct {
public int x;
public Struct next;
public static int f(int v){
return 2*v+1;
}
public static void testme(Struct p,int y){
if(y>0){
if(p!=null){
if(f(y)==p.x){
Cute.Assert(p.next!=p);
}
}
}
}
}
In concolic testing, we want to explore all possible distinct
execution paths of the function testme for all possible
values of its arguments p and x. For this we write
the following test driver function in the class
Struct. The test driver function represents the toplevel
function that is invoked to start the program execution. It can
be written in any other class and can have any name. The only
restriction is that it must be static and it should not have any
argument. jCUTE also considers a public static void
main(String args[]) as a potential driver function. jCUTE
graphical user interface lists all driver functions in a given
class. User can choose one of them to test concolically.
// test driver function
public static void driver() {
Struct s = (Struct)cute.Cute.input.Object("tests.Struct");
int y = cute.Cute.input.Integer();
testme(s,y);
}
In the test driver above we declare two variables s and
y. We then assign inputs to s and y. The
input function int cute.Cute.input.Integer() returns either a
random integer or a suitable integer computed by jCUTE through dynamic
analysis. Similarly, the input function Object
cute.Cute.input.Object(String classname), which takes the name of
a class as argument, returns a random object of type
classname or a suitable object computed by jCUTE through
dynamic analysis. Other similar functions for the remaining primitive
types of Java are as follows: byte
cute.Cute.input.Byte() These input functions can be used anywhere in the program. For example, in the program one can replace any occurrence of System.in.read() by cute.Cute.input.Integer() to indicate that jCUTE will provide appropriate input to the program rather than the user providing it. We can now test the function testme and generate JUnit test cases using jCUTE. To learn about how to use jCUTE check out a flash demo on jCUTE here. The JUnit test generated by jCUTE for the function testme can be found here. Testing Concurrent ProgramsTesting concurrent programs that accept data inputs is notoriously hard because, beside the large number of possible data inputs, nondeterminism in scheduling results in an exponentially large number of interleavings of concurrent events. jCUTE uses a novel testing algorithm for concurrent programs in which our goal is not only to execute all reachable statements of a program, but to detect all possible data races, and deadlock states. For concurrent programs, our algorithm uses the concrete execution to compute the exact race conditions between concurrent events. These race conditions are systematically permuted in subsequent executions to effectively find concurrency related bugs.jCUTE can be used to test multithreaded Java programs in a way similar to sequential programs. The user is not required to do anything special for testing multithreaded programs. jCUTE will efficiently exercise all relevant scheduling of threads while generating test inputs. However, we advice users to avoid generating JUnit test cases for multithreaded programs. This is because JUnit test cases can only provide inputs; they cannot provide directives to control the schedule of a multithreaded Java program. jCUTE generates and records the schedules internally. This enables an user to replay a multithreaded program. jCUTE also allows an user to view the trace of the program. |