Writing testable object-oriented code depends on sticking to proven best practices. One of the worst things you can do for the testability of your code is hard code a static lookup like this:

											
public void update() {
    String id = FacesContent.getCurrentInstance().getRequestMap().get("id");
    Widget w = dao.getByID(id);
    w.setDateModified(new Date());
    dao.update(w);
    FacesContext.getCurrentInstance().addMessage(null,
         new FacesMessage(SEVERITY_INFO, "Updated Object", "");
}
										

You will never get rid of the dependency on FacesContext.getCurrentInstance() from this code and you'll never be able to test it outside of the container. It's like pinning your class to the container with nail gun. Then you start pinning other classes here and there and soon the dependencies become impossible to unravel.

And that's all before you realize that accessing ThreadLocal variables clocks is about 10 to 20 times slower than accessing an object on the heap.

Unfortunately JSF actually encourages this bad practice by providing us with a static locator and using it throughout the source code and examples. We survived just fine for years without any HttpServletRequest.getCurrentInstance() locator, so why the sudden backflip? And how to you get out of the trap?

Dependency Injection

I imagine the static locator was included to provide better support for POJO managed beans. No implementing special constructors or interfaces, just a plain Java class with some static lookups and you're done.

Well actually, JSF provides a better solution to this problem via its support for property injection on managed beans. Here is how the original example looks using dependency injection:

											
@ManagedProperty("#{param.id}")
String id;

@ManagedProperty("#{facesContext}")
FacesContext faces;

public void update() {
    Widget w = dao.getByID(id);
    w.setDateModified(new Date());
    dao.update(w);
    faces.addMessage(null,
         new FacesMessage(SEVERITY_INFO, "Updated Object", "");
 }
										

When JSF executes this code it will set the id and faces properties for you but you can also execute this code outside the container by manually setting the id and faces properties before calling update() (you will need a mock FacesContext).

That solves the problem of testability but I still find it flaky. Without actually reading the source code there is no way to know I need to set an id and FacesContext before I call update().

Additionally, you can't inject a FacesContext into a @SessionScoped bean because it only lives for one request. It looks like JSF dependency injection has a few limitations.

We can do better.

EL Parameter Injection

How would you solve this in plain-old Java? Simple. You'd just pass the id and FacesContext reference around like this:

											
public void update(String id, FacesContext faces) {
    Widget w = dao.getByID(id);
    w.setDateModified(new Date());
    dao.update(w);
    faces.addMessage(null,
         new FacesMessage(SEVERITY_INFO, "Updated Object", "");
 }
										

Well, guess what. Now you can do that in JSF too. Since EL 2.2 you can call methods with parameters using EL instead of sticking to the JSF MethodExpressions which force you to stick to a well-defined method signature. Just call the method where appropriate:

											
<h:commandButton value="update"
                 action="${bean.update(param.id, facesContext)}"/>
										

I'm using the Glassfish EL-2.2 implementation in my apps:

											
<dependency>
  <groupId>org.glassfish.web</groupId>
  <artifactId>el-impl</artifactId>
  <version>2.2</version>
  <scope>compile</scope>
</dependency>
										

This makes it nearly impossible for me to forget to set up my dependencies during testing AND it also works without change on all request, view, conversion, session and any other scoped beans.

JSF converters, validators and components will pass the FacesContext as a parameter where necessary but be aware that UIComponent.getFacesContext() actually just defers to FacesContext.getCurrentInstance() which probably means that somewhere in your class hierarchy your component is nailed unceremoniously to the container. In that case your tests are going to have to include some sort of nasty hack to set a mock FacesContext for the current thread.