Search

ParaSoft

HOME
PRODUCTS
SUPPORT
ABOUT
WHAT'S NEW
EVENTS


Jtest

Quick Facts

Technical Papers

Support & Manuals

FAQs

Recent Reviews

User Testimonials

Press Releases

Jtest tool to debug Java(tm)





Contents  Previous  Next 

Lesson 6 - Using User-Defined Stubs


Stubs are basically replacements for references to external methods. For example, you could use stubs to specify that when the method "stream.readInt()" is invoked, Jtest should use the value 3 instead of actually invoking the readInt method.

Stubs are mainly used:

  • To isolate a class and test it independently of other classes, or
  • To test a class before the external classes it uses are available.

You can enter your own stubs for both automatic and user-defined test cases. When you configure Jtest to use your own stubs, you have complete control over what values or exceptions an external method returns to the class under test-- without having to have the actual external method completed and/or available.

Creating and Using User-Defined Stubs

There are 5 basic steps involved in creating and using user-defined stubs:

Step 1: Create a Stubs Class

Standard Procedure

The first step in using user-defined stubs is creating a Stubs Class. If you create a Stubs Class named "(name_of_class_under_test_Stubs)" and save it in the same directory as the class under test, you will not have to indicate the stub's location. You can use a class with a different name or location as long as you indicate the stub's location (as described in Step 3: Indicate the stub's location).

The main way to specify stubs is to create a Stubs Class: a class that contains one or more "stubs()" methods which define what (if any) return values or exceptions should be used for a certain input. Stubs Classes extend "jtest.Stubs". For information about jtest.Stubs, see the Jtest API javadoc (you can access this documentation by choosing Help> Jtest API).

Each Stubs Class should implement a method of the form:

 public static Object stubs (
    Method method // external method being invoked
    , Object _this // "this" if instance method
    , Object[] args // arguments to the method 
 // invocation
    , Method caller_method // method calling "method"
    , boolean executing_automatic  // true if executing
 	 	 	 	  //automatic Test Case
 );

Important: Only the first parameter is required; all others are optional. For example, you could define a "stubs() method" of the form "Object stubs (Method method)".

Whenever the class under test invokes a method "method" external to the class, Jtest will call the "stubs()" method. The "stubs()" method should declare what (if any) return values or exceptions should be returned for certain inputs. Use the following table to determine what type of return values or exceptions should be used for each possible stub type:

If you want the external method to return this . . .

Have the "stubs()" method return this . . .

no stub

NO_STUBS_GENERATED

void

VOID

a value

The value. If the value is a primitive type, it should be wrapped in an Object. For example, if "stubs()" decides that a given external call should return the integer 3, "stubs()" should return "new Integer (3)".

an exception

The exception that you want the stub to throw. For example, you could use something like:

throw new IllegalArgumentException ("time is:" + time);

Important: The "stubs()" method can only return an Object. To specify a return value of a primitive type, you need to wrap that type in an Object. For example, if you wanted to specify that the method

 int userMethod()

returned 3, you should have the "stubs ()" method return

 return new Integer (3)
 

To define stubs for constructor invocations, define a "stubs()" method whose first parameter is a constructor (instead of a method).

If some "stubs()" method is not defined, no stubs will be used for those members (method or constructor).

Stub Objects

Stub objects are very useful when writing user-defined stubs. A stub object is similar to any other object, with the following differences:

  • The stub object can be an instance of an interface. For example, the following creates an instance of "Enumeration":
    Enumeration enum = makeStubObject (Enumeration.class);
  • Any method invocation or field reference is a stub even if no stub has been defined for it. If no stub has been defined, Jtest will use a default stub returning the default initialization value for the method return type or field type (for example, "null" for Object, "0.0d" for double,etc.).

You need to use stub objects if you want to test classes that use interfaces for which an implementation has not yet been written. They can be used whenever an object of the interface class needs to be created.

Stub objects can also be used whenever you want to create an object of a given type without having to call a specific constructor. For example, instead of using "new java.io.FileInputStream ("what to put here?)", you could use: "(FileInputStream) JT.makeStubObject (java.io.FileInputStream.class)"; this creates a FileInputStream object.

For an example of how to use stub objects, assume that you have a class called StubObjects that uses the Interface Toaster. The Interface Toaster does not have an implementation.


Stub Objects.java

 import java.lang.reflect.*;
 
 public class StubObjects
 {
     public static int count (Toaster t1)
     {
         Toaster t2 = t1.copy ();
         int num = 0;
         if (t1.done ())
             num += t1.numSlices ();
         if (t2.done ())
             num += t2.numSlices ();
         return num;
     } 
 }

Toaster.java

 package examples.dynamic.stubs.userdef;
 
 interface Toaster
 {
     boolean done ();
     int numSlices ();
     Toaster copy ();
 }

Before you test the StubObjects class, you should call the Stubs Class called StubObjectsStubs because the methods copy(), numSlices(), and done() are not yet implemented in Toaster.

StubObjectsStubs.java

 class StubObjectsStubs extends jtest.Stubs
 {
     public static Object stubs (Method method)
     {
         String method_name = method.getName ();
 
         if (method_name.equals ("copy"))
             return makeStubObject (Toaster.class);
 
         if (method_name.equals ("done"))
             return Boolean.TRUE;
 
         return NO_STUB_GENERATED;
     }
 }

Note that the `makeStubObject()' method has been used in two places in this example:

  1. In the "stubs()" method.
  2. As the user-defined input for argument "t1" of method "count".

To test the StubObjects class, perform the following steps:

  1. In the Class Testing UI, open StubObjects.ctp (located in <jtest_install_dir>/examples/dynamic/stubs/userdef).
  2. Look at the user-defined input for argument "t1".
    1. Click Class to open the Class Test Parameters.
    2. In the Class Test Parameters window, open Dynamic Analysis> Test Case Generation> User Defined> Method Inputs> count> examples.dynamic.stubs.userdef.Toaster ARG1.

      Note that StubObject needed to be invoked as: "JT.makeStubObject (...)".


  3. Close the Class Test Parameters window.
  4. Run the test and view the stubs as described in Step 4: Run the test and Step 5: View the stubs.

    Note that even though we did not define stubs for the "numSlices" method, Jtest automatically generated a stub because the Toaster object was an object created with "makeStubObject()".

Using Stubs in Test Classes

If you are using a Test Class, you can define specific stubs for each test method by defining a "stubs()" methods within the Test Class. To specify the stubs for a test case defined by a "testXYZ" method, define a method of the form:

Object stubsXYZ (Method method, ...);

in that Test Class.

For example, assume that you wanted to use a Test Class to add inputs to MyFile.

MyFile

 package examples.dynamic.stubs.userdef;
 import java.util.*;
 
 
 public class MyFile
 {
    public int add (int i, int j) {
      return i + j;
    }
 }

If you wanted to include user-defined stubs in your Test Class, you might create a Test Class like MyFileTest.

MyFileTest

 package examples.dynamic.stubs.userdef;
 import jtest.*;
 
 
 import java.lang.reflect.*;
 import java.util.*;
      
 class MyFileTest extends TestClass
 {
    public static void testAdd () {
      MyFile mt = new MyFile();
      Integer Iop1 = (Integer) makeStubObject(Inte-
ger.class);
      Integer Iop2 = (Integer) makeStubObject(Inte-
ger.class);
      
       int op1 = Iop1.parseInt ("20");
       int op2 = Iop2.parseInt("10");
       int total = mt.add (op1, op2);
     
      assert ("total should be 30", total == 30);
    }
        
    public static Object stubsAdd (Method method, 
Object[] args)
    {
       String method_name = method.getName();
      if (method_name.equals("parseInt")) {
           String tempstring = (String) args[0];
           if (tempstring.equals("10"))
              return new Integer(10);
           if (tempstring.equals("20"))
              return new Integer(20);
           return new Integer(0);
       }
      
     
       return NO_STUB_GENERATED;
   }
 } MyFile

If a Test Class does not define a "stubs()" method, or if it does not return any stubs, Jtest will apply the Class and Project Test Parameters "stubs()" methods.

Step 2: Enable user-defined stubs

Jtest will not use your user-defined stubs unless it is configured to do so. By default, user-defined stubs are enabled for user-defined test cases, but disabled for automatically-generated test cases.

You can enable user-defined stubs at the global, project, or class level. To do so, open the appropriate parameters window, then:

  1. Open Dynamic Analysis> Test Case Execution> Stubs.
  2. Open either Options for Automatic Test Cases or Options for User Defined Test Cases.
  3. Enable the Use User Defined Stubs option.

Step 3: Indicate the stub's location

By default, when Jtest detects that the class under test references an external method, it searches for and uses Stubs Classes that are:

  • In the same directory as the class under test, and
  • Named <name_of_class_under_test>Stubs (for example, fooStubs.class).

If you do not change the default setting (Class Test Parameters' Dynamic Analysis> Test Case Execution> Stubs> Stubs Class value set to "$DEFAULT"), your Stubs Classes are named correctly, and your Stubs Classes are located in the same directory as the class under test, you do not need to indicate the stub's location.

If you need to indicate the Stubs Class location, right-click the Class Test Parameters' Dynamic Analysis> Test Case Execution> Stubs> Stubs Class node, choose Edit, then enter the location of the Stubs Class.

Important: If you specified your stub via a Test Class, you do not need to indicate the location of a Stubs Class.

Step 4: Run the test

If you have performed the above steps, Jtest will automatically use your stubs when you test the class or project in the normal manner.

Step 5: View the stubs

After you test a class using a user-defined stub, you can view the stubs in the User Defined Test Cases> Method Inputs> Method Name> Test Case> Test Case Input branch of the View Test Cases tree. User-defined stubs will be marked with a small black box. Each stub branch displays the method invoked as well as the value or exceptions returned by the stub. Expand the stub's branch to see the stack trace where the invocation occurred.


If the stub's values resulted in an error, the above information would also be displayed in the Errors Found Panel (if you were testing a class) or the Results panel (if you were testing a project).




Note: For additional examples, look at the following example files located in <jtest_install_dir>/examples/dynamic/stubs/userdef:

  • FileExampleStubs.java, FileExample.java
  • ConstructorExample.java
  • InterpreterTest.java, Interpreter.java (example of use of stubs within a TestClass).

Contents  Previous  Next 

ParaSoft logo
(888) 305-0041 info@parasoft.com Copyright © 1996-2000 ParaSoft