Mocking Static Calls Revisited

Yesterday I presented you with a problem we were facing with mocking out the static call to FacesContext.getCurrentInstance(). The three solutions I presented all felt wrong somehow. Comments showed a fourth option, AOP. Today I will present you with yet another solution, which I think feels right in every way.

Somehow everything seems easier once you take a look at the code. I already knew that FacesContext was a ThreadLocal variable. But only today, once I saw the code, I realized what I was missing. Basically the abstract base class javax.faces.context.FacesContext looks like the following:

public abstract class FacesContext {
	private static ThreadLocal _currentInstance = new ThreadLocal();

	// Lot of abstract methods.

	public static FacesContext getCurrentInstance() {
		return (FacesContext)_currentInstance.get();
	}

	protected static void setCurrentInstance(FacesContext context) {
		_currentInstance.set(context);
	}
}

This means that when we implement our own version of a FacesContext, we can have it set itself in the ThreadLocal! The solution lies in a MockFacesContextWrapper class implemented as follows:

public class MockFacesContextWrapper extends FacesContext {
	private FacesContext mockContext;
	
	public MockFacesContextWrapper(FacesContext context) {
		this.mockContext = context;
		FacesContext.setCurrentInstance(this);
	}

	// Delegate methods for mockContext for all declared abstract methods in FacesContext
}

Now your tests can be implemented using a mocked FacesContext without having your source code being aware that it's being tested. An example of a testcase:

public class SomeFacesBeanTest extends TestCase {
	private FacesContext facesContext;

	public void setUp() {
		facesContext = EasyMock.createMock(FacesContext.class);
		new MockFacesContextWrapper(facesContext);
	}
	
	// Your test methods.
}

I like that now the code under test does not need to be adapted. You can program as you're used to, without writing an indirection method to wrap the static call in, or introducing a new field in every class that uses the FacesContext. How do you rank it against the solutions presented yesterday in the blog and its comments?

Comments (5)

  1. Lars Vonk - Reply

    June 22, 2007 at 12:55 pm

    Good thinking Jeroen! It's an elegant solution, you only have to write the MockFacesContextWrapper once, and like you said the program is unware of Helpers etc. so I think we have a winner.
    The issue, how to mock static calls, is still valid though. Not all static calls are implemented like FacesContext which allow for this implementation. But thanks to your blogs we can now choose from 5 different solutions :-).

  2. Lonneke - Reply

    June 23, 2007 at 12:57 pm

    I really like this solution. I agree with you that it is better not do adapt the code under test. Besides that, this solution is easy to understand for developers that need to maintain it.

  3. Arnoud Wolfard - Reply

    July 25, 2007 at 3:03 pm

    Nice solution. Based on your code I came up with the code below (now you are not required to implement the abstract methods):

    public abstract class MockFacesContext extends FacesContext {

    public static void mockFacesContext(FacesContext facesContext) {
    FacesContext.setCurrentInstance(facesContext);
    }
    }

  4. Meindert - Reply

    September 11, 2007 at 9:08 am

    I just read an article about a aspectJ based mocking framework that can mock private/protected and static methods/constructors: http://www.testdriven.com/modules/news/article.php?storyid=577
    Maybe that is an option?

  5. Helgo Rongen - Reply

    October 25, 2007 at 2:35 pm

    You guys should also take a look at the Apache Shale Framework. It has a Test module which includes mock objects for the FacesContext.

    It works really well and all you have to do is implement the AbstractJsfTestCase from shale to get access to a (almost) fully mocked FacesContext.

Add a Comment