:: End of manually writing unit tests. Why not generate test cases automatically and smartly?

CUTE :: A Concolic Unit Testing Engine for C and Java

Open System Laboratory | Computer Science Department | University of Illinois at Urbana Champaign
Micro Tutorial for jCUTE

Unit Testing Sequential Programs

Suppose, 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()
short cute.Cute.input.Short()
long cute.Cute.input.Long()
float cute.Cute.input.Float()
double cute.Cute.input.Double()
char cute.Cute.input.Character()
boolean cute.Cute.input.Boolean()

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 Programs

Testing 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.

Copyright © 2006 University of Illinois at Urbana Champaign. All rights Reserved