Blog

Mocking Static Calls Revisited

22 Jun, 2007

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?

guest
5 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
Lars Vonk
15 years ago

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 :-).

Lonneke
15 years ago

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.

Arnoud Wolfard
Arnoud Wolfard
14 years ago

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);
}
}

Meindert
Meindert
14 years ago

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?

Helgo Rongen
Helgo Rongen
14 years ago

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.

Explore related posts