November 1, 2010

Removing Static Method Dependency via Adapters

There may come a time when you need to use static method calls in a method that you are creating or modifying. That is not a bad thing, per se, but the problem will arise once you try to unit test that method.

The idea behind a unit test is to test only the functionality in the method. To truly test only the functionality in the method however, you need to remove all of the outside dependencies. When you are testing a method that has a static method call, you can’t remove that dependency because there is no way to stub or mock a static method call. There is a work around for this dilemma that will allow you to mock out the static method call and truly unit test your method.

An adapter class is a class that allows you to wrap an instance class around the static class. The adapter class is just a pass through to the static class method, but once you have the adapter class, that class can implement an interface that you could mock out when unit testing.

Below, I will show you the original method with the static call and a step by step process to remove that dependency from your test.

Original method with static call

public bool LoadDB()
{
    bool result = true;
            
    // static method call
    result = pdDataBase.SetupDatabase();
            
    if (result && !_adapter.RefDataLoaded)
    {
        // static method call
        pdDataBase.LoadRefData();
    }

    return result;
}

What you see is a method that when we write the unit tests for we will be unable to remove the highlighted dependency. Using the adapter class process, we can remove these dependencies.

First thing is to create an adapter class for the static class that contains the method you need to remove. The adapter class is named the same as the static class, except has “Adapter” tacked on the end. You can give the class a name like  “StaticClassNameAdapter.vb”.

Inside that class file create an interface called “IStaticClassNameAdapter”. You could also create a separate interface class file as well. This interface is how you will communicate with the adapter class and by proxy to the static class. By communicating through the interface, you have the ability to mock out that interface so that you can return a known object when unit testing. Done this way, you will have a known object without having to touch web services, databases, etc.

public interface IpdDatabaseAdapter
{
     bool SetupDatabase();
     void LoadRefData();
}

public class pdDatabaseAdapter : PigskinDraftRepository.Adapters.IpdDatabaseAdapter
{
     public bool SetupDatabase()
     {
         return pdDataBase.SetupDatabase();
     }

     public void LoadRefData()
     {
         pdDataBase.LoadRefData();
     }
}

The interface will contain a method definition that mirrors the static method call. When the adapter class implements the interface, that method can call the static method. This seems like a lot of work to handle a static method, but this can give you a lot of flexibility moving forward as well as a way to test methods now.

Once we have the adapter class and the interface, you will make two changes to the class that contains the method that originally called the static method.

Add a new parameter to the constructor of the class that is of type of the interface you created for the adapter.

private IpdDatabaseAdapter _adapter;

public MainPresenter(IpdDatabaseAdapter adapter)
{
   _adapter = adapter;  
}

Change the method call to call the adapter instead of the static class method.

public bool LoadDB()
{
     bool result = true;
     result = _adapter.SetupDatabase();

     if (result && !_adapter.RefDataLoaded)
     {
         _adapter.LoadRefData();
     }

     return result;
}

Using adapter interfaces and classes around static method does not change the underlying functionality of the method. All this does is gives us the ability to remove a dependency from the method when we want to unit test that method.

What are some other options to remove static method call dependencies from methods for unit testing purposes?

Here are some additional links if you want further research:

www.javaranch.com/journal/200709/dependency-injection-unit-testing.html

googletesting.blogspot.com/2008/12/static-methods-are-death-to-testability.html

elegantcode.com/2008/01/05/adapt-those-static-methods/

2 comments:

  1. I use this approach whenever I write code that has date/time logic. A "SystemClockAdapter" class that wraps DateTime.Now makes it easy to test code branches that only execute during certain parts of the day.

    If you're trying to retrofit this approach into legacy code, I've found that "poor man's dependency injection" works great. Instead of making the adapter instance a required constructor argument, make it optional. In the default constructor, just new up an instance of the adapter you created. This allows you to inject an instance during testing but doesn't force you to modify every existing call site.

    ReplyDelete
  2. Another option is to *not* remove static method call dependencies, but to *mock* them. There are mocking tools for that.

    ReplyDelete