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?