Remember the Abstract Factory Pattern

With all the emphasis these days on unit testing it amazes me that I see developers are still dropping bombs like…

  1 public void someMethodThatMyUnitTestHasToCall(){
  2        ... Method Logic ...
  3        SuperComplexObject object = new SuperComplexObject();
  4        object.doSomethingThatIDesperatelyWantToAvoidForMyTest();
  5        // or an alternatively horrific call
  6        DifferentClass.staticMethodCallWhichCallsSomethingElseIWantToAvoid();
  7 }

Nothing kills a unit test faster than near un-mockable behavior in the middle of a method call which you can’t avoid (at least in java).  Types of actions taken in these undesirable method calls and object creations are generally database activity or some type of HTTP access when cause you to write more code to setup a unit test than the code under test itself. Many cases can be refactored with simply making the object an instance variable, however when an object has a lot of state which shouldn’t be retained from call to call thats not an option. I want to remind folks in these cases of the Abstract Factory Pattern which is a very straight forward way to wrap these monsters up. Sometimes people may avoid the exact pattern because it involves creating an extra class and interface in its pure form which sometimes is undesirable especially if you have a lot of classes which need to be hidden,  so I’ll offer a variation on the pattern which hopefully will make it more palatable.

Modified Abstract Factory

The modified abstract factory I’ll suggest is simply a single class that encapsulates the unwanted call. For Object creation it will always be the actual “new Object()” statement because if you can’t get another instance type created your out of luck. In the case of static method calls its the method call itself.

  1 public class ComplexObjectFactory {
  2    public ComplexObject getComplexObject(){
  3        ComplexObject object = new ComplexObject();
  4        return object;
  5    }
  6 }

Injecting the Factory

Now we need to get the factory into the class somehow there are a couple of ways to do this…

  • Pass a factory instance in as new parameter
  • Create a settable field in the class for the new factory

Depending on the situation you could have a other options as well but the one option that isn’t there is just replacing “new Object()” with “new ObjectFactory()” that won’t get you any closer to solving the problem with the suggested solution I’m providing. Now you can see how the old method changes.

  1 ComplexObjectFactory factory = new ComplexObjectFactory();
  3 public void methodCalledByUnitTest(){
  4    ComplexObject object = factory.getComplexObject();
  5    object.complexMethodCall();
  6 }
  8 public void setComplexObjectFactory(ComplexObjectFactory factory) {
  9     this.factory = factory;
 10 }

Unit Test Mocking

Now there is a hook to where you can create an extension of the quasi abstract factory class which returns a mock instance of your class or returns mocked data for a static method call.

  1 ComplexObjectFactory factory = new ComplexObjectFactory() {
  2      public ComplexObject getComplexObject() {
  3           //Mock up the behavior in someway.
  4           return new MockComplextObject():
  5      }
  6 };

All you need to do is set the new factory implementation. This will allow your unit test to focus on the code under test not the code that was tangentially called by the code under test (assuming thats your testing methodology).


Tags: , , , ,

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: