Using Custom 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.
There are 5 basic steps involved in creating and using user defined stubs:
- Create the custom stub.
- Enable the custom stub.
- Indicate the stub's location.
- Test the class in the normal manner.
- View the stubs.
Creating a Custom Stub
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 Indicating the Stub's Location below).
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.
Defining 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. For example, 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.
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.
For more information on Test Classes, see Adding Test Classes
Defining Stubs at the Project Level
If more than one of the classes in your project uses the same "stubs ()" method, you should create a project-level Stubs Class that contains the return values for that method. Project-level stubs should be created like class-level stubs. The only differences between project-level stubs and class-level stubs are:
- Class-level stubs contain stubs specific to a class, whereas project-level stubs contain stubs that can be shared by multiple classes.
- You indicate the location of class-level stubs in the Class Test Parameters Dynamic Analysis> Test Case Execution> Stubs> Stubs Class branch, but you indicate the location of project-level stubs in the Project Test Parameters Dynamic Analysis> Test Case Execution> Stubs> Stubs Class branch.
When Jtest tests a class in the project, it will first apply the Stubs Class indicated in the Class Test parameters. If no stub is generated at the class level, Jtest will apply the Stubs Class indicated at the project level.
Enabling 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:
- Open Dynamic Analysis> Test Case Execution> Stubs.
- Open either Options for Automatic Test Cases or Options for User Defined Test Cases.
- Enable the Use User Defined Stubs option.
Indicating 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 for a specific class, 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.
If you want to indicate the Stubs Class's location at the project level, right-click the Project Test Parameters' Dynamic Analysis> Test Case Execution> Stubs> Stubs Class node, choose Edit, then enter the location of the Stubs Class.
Important: If you specify a Stubs Class at the project level, Jtest will first apply the Stubs Class indicated in the Class Test parameters. If no stub is generated at the class level, Jtest will apply the Stubs Class indicated at the project level. Jtest will not automatically search for Stubs Classes at the project level.
If you specified your stub via a Test Class, you do not need to indicate the location of a Stubs Class.
Running 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.
Viewing the Stubs
After you test a class using a user defined stub, you can view the stubs in the User Defined Test Cases> 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 will also be displayed in the Errors Found Panel (if you are testing a class) or the Results panel (if you are testing a project).
Summary
If you want Jtest to use user defined stubs:
- Create a Stubs Class whose "stubs ()" methods indicate what (if any) values or exceptions you want the stub to return.
- Enable user defined stubs in the appropriate test parameters window.
- If your Stubs Class is not named (name_of_class_under_test)Stubs and is not in the same directory as the class under test (or, if your Stubs Class should be applied at the project level), indicate the stub's location.
- Test the class as normal.
Related Topics
About Dynamic Analysis
Performing Dynamic Analysis
Customizing Dynamic Analysis
Testing Classes That Reference External Resources
Setting an Object to a Certain State
|