Mock Objects in Unit Tests by
Lu jian
01/12/2005
.
EasyMock is a well-known mock tool that can create a mock object for a given interface at runtime. The mock object's behavior can be defined prior encountering the test code in the test case. EasyMock is based on
Java.lang.reflect.Proxy, Which Crete Dynamic Proxy Classes / Objects According To Given Interfaces. But it has an inherent limited from ITS using Of
Proxy: It can create Mock Objects Only for interfaces.
MoCquer Is A Similar Mock Tool, But One That Extends The FunctionAlity Of Easymock To Support Mock Object Creation for Classes As Well As Interfaces.
Introduction to Mocquer
Mocquer is based on the Dunamis project, which is used to generate dynamic delegation classes / objects for specific interfaces / classes. For convenience, it follows the class and method naming conventions of EasyMock, but uses a different approach internally.
..
Life Cycle Control Methods
Public void replay ();
Public void verify ();
Public void reset ();
The mock object has three states in its life cycle: preparing, working, and checking Figure 1 shows the mock object life cycle Figure 1. Mock object life cycle Initially, the mock object is in the preparing state The mock object's behavior can... be defined in this state. replay () changes the mock object's state to the working state. All method invocations on the mock object in this state will follow the behavior defined in the preparing state. After verify () is called, the mock object is . in the checking state MockControl will compare the mock object's predefined behavior and actual behavior to see whether they match The match rule depends on which kind of MockControl is used;. this will be explained in a moment The developer can use replay () to. Reuse the predefined behavior if Needed. Call Reset (), in Any State, To Clear The History State. Factory MethodSpublic Static MockControl CreateniceControl (...);
Public Static MockControl CreateControl (...);
Public Static MockControl CreateStrictControl (...);
Mocquer provides three kinds of MockControls: Nice, Normal, and Strict The developer can choose an appropriate MockControl in his or her test case, according to what is to be tested (the test point) and how the test will be carried out (the. test strategy). The Nice MockControl is the loosest. It does not care about the order of method invocation on the mock object, or about unexpected method invocations, which just return a default value (that depends on the method's return value). The Normal MockControl is stricter than the Nice MockControl, as an unexpected method invocation on the mock object will lead to an AssertionFailedError. The Strict MockControl is, naturally, the strictest. If the order of method invocation on the mock object in the working state is different than that in the preparing state, an AssertionFailedError will be thrown. The table below shows the differences between these three kinds of MockControl.NiceNormalStrictUnexpected OrderDoesn't careDoesn't careAssertion FailedErrorunexpected methodDefault valueassertionFailederRORASSERTIONFAILEDEDERRORASSSSERTIONFAILDERROR THEN ARE TWO VERSIONS for Each Factory Method.
Public Static MockControl CreatexxxControl (Class Clazz);
Public Static MockControl CreatexxxControl (Class Clazz,
Class [] argtypes, object [] args);
If the class to be mocked is an interface or it has a public / protected default constructor, the first version is enough. Otherwise, the second version factory method is used to specify the signature and provide arguments to the desired constructor. For example, assuming ClasswithNodefaultconstructor is a class welch a default constructor:
Public class classwithndefaultconstructor {
Public ClasswithNodeFaultConstructor (INT i) {
...
}
...
}
The MockControl Can Be Obtained THROUGH: MockControl Control = MockControl.createControl
ClasswithNodefaultconstructor.class,
New class [] {integer.type},
New Object [] {new integer (0)});
Mock Object Getter Method
Public Object getmock ();
.
// Get Mock Control
MockControl Control = MockControl.createControl (foo.class);
// Get The Mock Object from Mock Control
Foo foo = (foo) Control.getmock ();
Behavior Definition Methods
Public void setReturnValue (... Value);
Public void setthrowable (throwable throwable);
Public void setvoidcallable ();
Public void setDefaultreturnValue (... Value);
Public void setDefaultthrowable (throwable throwable);
Public void setdefaultvoidcallable ();
Polic void setmatcher (argumentsmatcher matcher);
Public void setDefaultmatcher (argumentsmatcher matcher);
MockControl allows the developer to define the mock object's behavior per each method invocation on it. When in the preparing state, the developer can call one of the mock object's methods first to specify which method invocation's behavior is to be defined. Then, the developer can Use One of the Behavior Definition Methods To Specify The Behavior. For Example, Take The Following Foo Class:
//Foo.java
Public class foo {
Public void dummy () throw parseException {
...
}
Public String Bar (INT i) {
...
}
Public Boolean Issame (String [] strs {
...
}
Public Void Add (StringBuffer SB, String S) {
...
}
}
The Behavior of The Mock Object Can Be Defined As in The Following:
// Get Mock Control
MockControl Control = MockControl.createControl (foo.class);
// Get Mock Object
Foo foo = (foo) Control.getmock ();
// begin Behavior Definition
// Specify Which Method Invocation's Behavior
// TO BE Defined.
FOO.BAR (10);
// define the behavior - return "ok" WHEN THE
// argument is 10
Control.setReturnValue ("OK");
...
// end behavior definition
Control.Replay ();
...
Most of the More Than 50 Methods in MockControl Are Behavior Definition Methods. They Can Be Grouped Into Following Categories.
setReturnValue () These methods are used to specify that the last method invocation should return a value as the parameter. There are seven versions of setReturnValue (), each of which takes a primitive type as its parameter, such as setReturnValue (int i) or setReturnValue (float f). setReturnValue (Object obj) is used for a method that takes an object instead of a primitive. If the given value does not match the method's return type, an AssertionFailedError will be thrown. It is also possible to add the Number of expected invocations INTO The Behavior Definition. this is called the invocation times limited.
MockControl Control = ...
Foo foo = (foo) Control.getmock ();
...
FOO.BAR (10);
// define the behavior - return "ok" WHEN THE
// argument is 10. and this method is expected
// to be caled just overce.
SetReturnValue ("OK", 1);
...
The Code Segment Above Specifies That The Method Invocation, Bar (10), Can Only Occur Once. How About Providing A Range?
...
FOO.BAR (10);
// define the behavior - return "ok" WHEN THE
// argument is 10. and this method is expected
// to be called at Least Once And At Most 3
// Times.
SetReturnValue ("OK", 1, 3);
...
NOW BAR (10) Is Limited to Be Called At Least Once and at Most, Three Times. More Appealingly, A Range Can Be Given To Specify The Limitation ....
FOO.BAR (10);
// define the behavior - return "ok" WHEN THE
// argument is 10. and this method is expected
// to be caled at Least Once.
SetReturnValue ("OK", Range.one_OR_MORE);
...
Range.ONE_OR_MORE is a pre-defined Range instance, which means the method should be called at least once. If there is no invocation-count limitation specified in setReturnValue (), such as setReturnValue ( "Hello"), it will use Range. ONE_OR_MORE as its default invocation-count limitation there are another two predefined Range instances:. Range.ONE (exactly once) and Range.ZERO_OR_MORE (there's no limit on how many times you can call it) there is also a special set return value. method:... setDefaultReturnValue () It defines the return value of the method invocation despite the method parameter values The invocation times limitation is Range.ONE_OR_MORE This is known as the method parameter values insensitive feature.
...
FOO.BAR (10);
// define the behavior - Return "ok" WHEN CALING
// Bar (int) despite the argument value.
SetDefaultReturnValue ("OK");
...
setThrowable setThrowable (Throwable throwable) is used to define the method invocation's exception throwing behavior. If the given throwable does not match the exception declaration of the method, an AssertionFailedError will be thrown. The invocation times limitation and method parameter values insensitive features can also be Applied.
...
Try {
Foo.dummy ();
} catch (exception e) {
// Skip
}
// define the behavior - throw parseException
// When Call Dummy (). and this method is expected
// to be caled exactly overce.control.setthrowable (New Parseexception (", 0), 1);
...
SetvoidCallable () setvoidcallable () is used for a Method That Has A Void Return Type. The Invocation Times Limitation and Method Parameter Values Insensitive Features Can Also Be Applied.
...
Try {
Foo.dummy ();
} catch (exception e) {
// Skip
}
// define the behavior - no return value
//hen caling dummy (). and this method is expected
// to be caled at Least Once.
Control.setvoidCallable ();
...
Set ArgumentsMatcher In the working state, the MockControl will search the predefined behavior when any method invocation has happened on the mock object There are three factors in the search criteria:. Method signature, parameter value, and invocation times limitation The first and third factors. are fixed. The second factor can be skipped by the parameter values insensitive feature described above. More flexibly, it is also possible to customize the parameter value match rule. setMatcher () can be used in the preparing state with a customized ArgumentsMatcher.
Public interface argumentsmatcher {
Public Boolean Matches (Object [] Expected,
Object [] actual);
}
The only method in ArgumentsMatcher, matches (), takes two arguments. One is the expected parameter values array (null, if the parameter values insensitive feature applied). The other is the actual parameter values array. A true return value means that the parameter VALUES MATCH.
...
Fuo.issame (null);
// set the argument match rule - Always Match
// no matter what parameter is given
Control.setmatcher (MockControl.Always_matcher);
// define the behavior - Return True When Call
// issame (). and this method is expected
// to be caled at Least Once.
Control.setReturnValue (TRUE, 1); ...
There are three predefined ArgumentsMatcher instances in MockControl. MockControl.ALWAYS_MATCHER always returns true when matching, no matter what parameter values are given. MockControl.EQUALS_MATCHER calls equals () on each element in the parameter value array. MockControl.ARRAY_MATCHER is almost the same as MockControl.EQUALS_MATCHER, except that it calls Arrays.equals () instead of equals () when the element in the parameter value array is an array type. of course, the developer can implement his or her own ArgumentsMatcher. A side effect of a customized Argumentsmatcher Is That It Defines The Method Invocation's Out Parameter Value.
...
// Just to DemonStrate the function
// of out parameter Value Definition
foo.add (new string "; {null, null};
// set the argument match rule - Always
// Match no matter what parameter given.
// Also Defined The Value of Out Param.
Control.setmatcher (new argumentsmatcher () {
Public Boolean Matches (Object [] Expected,
Object [] actual) {
(StringBuffer) actual [0])
.append (actual [1]);
Return True;
}
});
// define the behavior of add ().
// this Method Is Expected to Be Called AT
// Least Once.
Control.setvoidCallable (True, 1);
...
setDefaultMatcher () sets the MockControl's default ArgumentsMatcher instance. If no specific ArgumentsMatcher is given, the default ArgumentsMatcher will be used. This method should be called before any method invocation behavior definition. Otherwise, an AssertionFailedError will be thrown.
// Get Mock Control
MockControl Control = ...;
// Get Mock Object
Foo foo = (foo) Control.getmock ();
// set default argumentsmatcher
Control.SetDefaultMatcher
MockControl.Always_matcher);
// Begin Behavior Definitionfoo.bar (10);
Control.setReturnValue ("OK");
...
If setdefaultmatcher () is not used, MockControl.Array_matcher is the system default argumentsmatcher.