jeudi, mars 22, 2007

Mocking, Stubbing, and Usurping

This post won't be about mockery in general, nor will it be about a famous "Love boat" captain (ok ...not the same "spelling" ;) ).

What I want to talk about is Mock Objects and Stubs used in strategies for Unit Testing.

When you have to Unit test a piece of code, (if your purpose is really to Unit test it), you'll often need to isolate it from the surrounding layers/components.

In order to achieve this, two common tools are used: Mocks and Stubs (Though other variants are available).

Let's begin with Stubs (in unit testing vocabulary). A Test Stub is a test-specific implementation of the contract of the object/component it is supposed to replace. It is ment to return the value this component is supposed to return. This Stub can also return a wrong value or throw an Exception in order to emulate error cases and test the robustness of our system under test.

A Mock object adds some behaviour testing to the Stub. This means that in addition to the returning of values and throwing of exceptions, it also checks the input it gets from the system under test, the number of times each method has been called...etc

So why does this post's title mentions Usurping?

Now comes the part where I'll present a solution I came up to for Java applications and baptized Usurper.

When you're creating your own Stubs or using a Mock Object framework (easymock, jmock...etc) you need to feed them with the expected return values.

It can sometimes be quite tedious to create a value object's instance, and even more if your Mocked component is supposed to return a list of 100 users for example.

This is where Usurper comes in handy.

If you have a User Value Object like this one:

public class User{
private String firstName;

private String lastName;

private Integer age;

private boolean administrator;

// getters and setters ...toString() method...
}

Here's how you can create a list of 100 User objects using Usurper.

// CREATE THE USURPER GENERATOR
UsurperGenerator<User> userGenerator
= new UsurperGenerator<User>(User.class);

// GENERATE A LIST OF USER VALUE OBJECTS
List<User> userList =
userGenerator.generateUsurperList(100);
And you're done!

At least for now if you don't need to test the contents of the object.
In fact, the content of the generated usurper object is something like this:

org.org.usurper.User@1632c2d[
lastName=dCOuSJOZQZ
administrator=false
age=814857147
firstName=Zq8R9bH7LJ
]
This is because the default field handlers allocate a random value to the fields in your object.
So this is the part where you'll say to me this is no use at all.
Well I'll answer that from now on this is up to you!!! ;)
You can easily implement:
This way you can customize the way some fields are dealt with.
For example, the BigInteger type is not handled by default. You can easily create your own implementation in a global text fixture of to a specific test's local fixture:

// CREATE THE USURPER GENERATOR
UsurperGenerator<User> userGenerator =
new UsurperGenerator<User>(User.class);

// REGISTER CUSTOM PROPERTY TYPE HANDLER
Set<Class> handledTypes = new HashSet<Class>();
handledTypes.add(BigInteger.class);
userGenerator.registerPropertyTypeHandler(
new AbstractPropertyTypeHandler(handledTypes) {
public Object handle(Object targetObject, Class attributeClass,
String attributeName, Map parentHandlers) {
return new BigInteger(24, new Random());
}
});

// GENERATE A LIST OF USER VALUE OBJECTS
List<User> userList =
userGenerator.generateUsurperList(100);


This is just one basic (and probably meaningless) example of what you can easily do with Usurper.

Note that Usurper supports by default:
  • Generation of array properties: if your property is a BigInteger[], all you have to do is define a handler for the BigInteger type.
  • Generation of Collection properties: if your property is a List<BigInteger>, Set<BigInteger> or Map<BigInteger,BigInteger>, all you have to do is also to define a handler for the BigInteger type.
  • Generation of Enum properties: a default handler gives random values for Enum types.
  • Generation of Value Object properties: if your property is another value object, you can easily register it through the use of the ValueObjectPropertyTypeHandler.
If you want to learn more, and hopefully give it a try and adopt it (it is LGPL licensed), follow this link:
http://www.org-libs.org/org-lib-usurper