Ever since I started using TDD (test driven development) methods in my work, I never stopped. I rarely start a project without knowing how I’ll test it, and not just in Java: C#, Objective-C, and Python as well. I’ve found that TDD can be done in the most unlikely places, such as servlets using Cactus or Java EE using MockRunner.
However, when I started working with Project Darkstar recently, it seemed impossible to test. Mostly, because it requires you to use their interface, ManagedReference, to contain references between serialized objects (you can decide not to use them, but then performance goes down significantly). The problem is not with the interface but with the way it’s created, which is only by using the DataManager they provide, using the AppContext.getDataManager() method.
This is a problem, because to keep a ManagedPlayer object which holds a reference to a ManagedWeapon, you might have the code:
public final class ManagedPlayer implements ManagedObject, Serializable {
private ManagedReference<ManagedWeapon> weapon;
public void setWeapon(ManagedWeapon weapon) {
// alert early-on that this object is going to change; prevents
// collisions later.
AppContext.getDataManager().markForUpdate(this);
// sets the weapon as a managed reference
this.weapon = AppContext.getDataManager().createReference(weapon);
}
// ... the rest of the class
}
Within the Darkstar runtime context, this works great. However, within a JUnit context, this will fail as AppContext.getDataManager() will return null, and the code will throw an NPE.
For that reason, I have created a set of mocks, and I thought I’d share them in case someone wants to make this into a bigger project, Mockstar or something.
First, I created an interface to abstract everything to do with ManagedReference. Since ManagedObject is just a marker interface, I don’t care much about it; however, the creation of ManagedReference, and the creation of the scalable versions of Set and Map (ScalableHashSet and ScalableHashMap, respectively):
public interface ManagedFactory {
<T> ManagedReference<T> createReference(T item);
void markForUpdate(Object item);
<T> Collection<T> createCollection();
<T, K> Map<T, K> createMap();
}
Now, the previous code could be written as:
public final class ManagedPlayer implements ManagedObject, Serializable {
private ManagedFactory factory; // initialized in ctor
private ManagedReference<ManagedWeapon> weapon;
public void setWeapon(ManagedWeapon weapon) {
factory.markForUpdate(this);
this.weapon = factory.createReference(weapon);
}
// ... the rest of the class
}
The following are the implementations of MockManagedReference, DarkstarManagedFactory and MockManagedFactory:
MockManagedReference
Note that this class is serializable as to not break the original ManagedReference’s implementation’s intention.
public class MockManagedReference<T> implements ManagedReference<T>, Serializable {
private static int globalId = 1;
private T item;
private int id;
public ManagedReferenceMock(T item) {
this.item = item;
this.id = globalId++;
}
public T get() {
return item;
}
public T getForUpdate() {
return item;
}
public BigInteger getId() {
return BigInteger.valueOf(id);
}
}
DarkstarManagedFactory
This class is the one you would really use in the Darkstar context.
public final class DarkstarManagedFactory implements ManagedFactory {
public <T> ManagedReference<T> createReference(T item) {
return AppContext.getDataManager().createReference(item);
}
public void markForUpdate(Object item) {
AppContext.getDataManager().markForUpdate(item);
}
public <T> Collection<T> createCollection() {
return new ScalableHashSet<T>();
}
public <T, K> Map<T, K> createMap() {
return new ScalableHashMap<T,K>();
}
}
MockManagedFactory
This class will be used in a unit testing context.
public class ManagedObjectFactoryMock implements ManagedObjectFactory {
public <T> ManagedReference<T> createReference(T item) {
return new ManagedReferenceMock<T>(item);
}
public void markForUpdate(Object item) {
// empty.
}
public <T> Collection<T> createCollection() {
return new HashSet<T>();
}
public <T, K> Map<T, K> createMap() {
return new HashMap<T,K>();
}
}
Conclusion
I couldn’t find anything in my searches for a mock system for Darkstar. If someone knows of any, please let me know. On the other hand, if someone actually does something with what I wrote, I would be even more interesting in knowing!
