Testable Code when Dealing with Third Party Singletons

There are some old frameworks out there that makes you deal with Singletons or static methods.

In addition, those frameworks may ask you to declare your objects with your business logic, in configuration files, in order the framework can manage them for you. These old frameworks have not yet entered in the world of dependency injection. They still makes you deal with Singletons and does not give you the ability to inject those Singletons from outside (constructor injection or setter injection), due to they manage your objects.

So, you don’t have other choice than hard code these Singleton dependencies into your business logic object (or upgrade the framework version which might involve some extra time). Hard coding Singletons or static calls on your business logic makes your object hard to unit test. In the next code snippet you will see an easy way to deal with this.

package ar.cpfw.thirdparty;

public class EvilThirdPartySingleton {

  private final static EvilThirdPartySingleton INSTANCE =
      new EvilThirdPartySingleton();

  private EvilThirdPartySingleton() {

  }

  public static EvilThirdPartySingleton getInstance() {
    return INSTANCE;
  }

  public String getValue(String aKey) {
    // some complex query to give you a value
    // from a configuration based on aKey
    return "... someValue ... ";
  }
}

package ar.cpfw.myobjects;

import ar.cpfw.thirdparty.EvilThirdPartySingleton;

/**
 * An object managed by a third party framework
 * */
public class MyUnderTestObject {

  public void nonUnitTestableMethod() {
    // some logic here...
    // . . .

    // then, a call to the evil Singleton
    String aValue =
        EvilThirdPartySingleton.getInstance().getValue("aKey");

    // do more something with aValue
    // ...
  }

  public void unitTestableMethod() {

    // some logic here...
    // . . .

    // then, a call to the evil Singleton
    String aValue = getValue("aKey");

    // do more logic with aValue
    // ...
  }

  protected String getValue(String aKey) {
    return EvilThirdPartySingleton.getInstance().getValue(
        "aKey");
  }
}

import org.junit.Test;

public class MyUnderTestObjectTest {

  @Test
  public void my_logic() {

      //set up
      MyUnderTestObject myObject = new MyUnderTestObject() {
          @Override
          protected String getValue(String aKey) {
              // just return the friendly value
              // you need for your test
              return "aFriendlyTestValue";
          }
      };

      //call the method under test
      myObject.unitTestableMethod();

      //verify ...

  }
}

The EvilThirdPartySingleton is the Singleton we have to deal with, that belongs to a third party framework. The MyUnderTestObject is the object that implements some functionality of my application and is managed by a third party framework. This object has two informative methods. The name of the methods explain the intention of each one. Basically, one has hard coded the reference to the Singleton and the other access to the Singleton through a protected method. Finally, in the test class, MyUnderTestObjectTest, we stub the Singleton call by overriding the protected method.

You may be thinking that we are stubbing the object under test, and you will be right. But I’m not stubbing the method under test.
Ideally, we should inject all the depedencies, as is described very well in this video by Misko Hevery. But sometimes it is not possible for the reasons described above.

Is this an evil alternative solution? looking forward to read your thoughts…

Posted in Testing Tagged with: , ,