directly in Java classes makes managed beans more difficult to unit
test. This post discusses how to mock the context for testing outside
the application container.
javax.faces.beanannotations but the techniques apply for other bean management mechanisms (e.g. using
- Understanding the Lifecycle of the FacesContext
- Mocking for FacesContext.getCurrentInstance()
- Designing for Test with Dependency Injection
- Dependency Injection and Scopes
- End Notes
Understanding the Lifecycle of the FacesContext
It is important to note that even though you can reference it via
a static method that the
FacesContext is not
FacesContext is a request-scope artifact. At the
start of a request, the controller (e.g. servlet or portlet) will create
a new context using the
When it is created, it assigns itself to a
static variable so that it can be referenced via
At the end of the request the controller calls
to dispose of the context.
Outside of a request, a limited context is made available during application startup and shutdown when only certain documented methods can be called.
A HTTP request in a portlet container may cause the creation and
release of a number of
FacesContexts as the individual
portlets and their scopes are processed.
Mocking for FacesContext.getCurrentInstance()
Here is a managed bean that acquires the
via a static call:
This managed bean increments a session-scoped integer when
To test this I've implemented a utility class that sets the mock
For completeness I've added code to release the context for garbage collection at the end of the test. You can omit this code if you don't mind the leak.
The unit test looks like this:
Designing for Test with Dependency Injection
Static calls aren't the only way to reference the
The context is also provisioned via the
request scope variable.
In this version of the bean the context is injected by the framework before the bean is placed into scope:
Because the test doesn't instantiate the bean via a resolver the test must set the mock context explicitly:
Dependency Injection and Scopes
JSF's managed properties prevent the injection of narrowly scoped
artifacts into broader scopes. This helps prevent stale objects leaking
out of scope. It also means that you can't inject
as a managed property into scopes broader than the request scope.
An application scoped utility bean can be used to overcome this problem:
The class is serializable to allow it to work in sessions that are passivated out of memory. See the servlet specification for more details.
Managed beans must always reference the context via this broker:
The corresponding unit test:
- Java 6
- JSF 2
- JUnit 4
- Mockito 1.8