Test JSF Applications with Embedded Server
Preface
JSF is very complicated framework, with a lot of tight related components, that makes testing pretty complicated. It runs inside Servlet container, and framework behavior depends from container configuration. The goal of embedded servlet container is providing flexible test environment suitable to test parts of JSF application: Composite components, view fragments and templates. The idea is very similar to Jboss Arquilian framework, with some JSF-specific extensions. The main answer to the question why to not use Arquillian to test RichFaces components is what it was introduced far before Jboss implementation. Another answer is JSF-specific features and speed, embedded stage server runs much faster real implementations.
Features
- Container runs in the same thread that performs client request, what allows test code to inspect request-scope objects, or even interrupt request processing for asserts.
- Container configuration made from the java code, that lets every test has its own settings and web application content. For example, the same test can be invoked with different initialization parameters.
- Extremely fast, container doesn’t parese any configuration files, setup network connections or instantiate multiply applications.
- Single Java object holds container instance, therefore it can be used with any test framework.
- Integration with HtmlUnit to simulate web client.
Limitations
- No JSP compiler, only Facelets views can be used.
- Ignores web.xml content. Container should be configured from Java code.
- No network access
- No JNDI, no injection, only base javax.servlet interfaces.
- No transactions
- By default, FacesServlet initialized with suffix-based mapping ‘*.jsf’.
Usage
Instantiation of FacesEnvironment
jUnit 4 test class fragment:
private FacesEnvironment environment;
@Before
public void setUp() {
environment = FacesEnvironment.createEnvironment().start();
}
@After
public void thearDown() throws Exception{
environment.release();
}
This code creates an instance of environment, initializes JSF framework and starts server instance before each test, and releases resources after test. The version of this method with ApplicationServer parameter lets create environment for different server implementation ( currently, embedded Jetty server supported ).
Configuration
FacesEnvironment class has set of configuration methods to describe web application context and setup server. all methods returns back the same instance, so they can be chained:
withContent(String,String) – define content of web resource for given path:
environment = FacesEnvironment.createEnvironment().withContent(“/test.xhtml”,
“<html xmlns=\”http://www.w3.org/1999/xhtml\”\n” +
” xmlns:ui=\”http://java.sun.com/jsf/facelets\”\n” +
” xmlns:h=\”http://java.sun.com/jsf/html\”>”+
“<h:form id=\”helloForm\” >”+
” <h:outputText value=\”foo_bar\” />\n” +
“</h:form>\n” +
“</html>”).start();
withResource(String,String) – put content of classpath resource to the given path in servlet context.
withWebRoot(String) – create virtual web server context from the package containing given resource. Suitable to create web application fragment from resources stored in the jar. Another way to create vitrual servlet context is system property ‘webroot’, that should contain path to the folder with web application content.
withResourcesFromDirectory(String path, URL resource) – Add all resources from the directory to the virtual web application content. Only ‘file’ or ‘jar’ protocols are supported. If this parameter points to a file, it will be converted to a enclosing directory.
withInitParameter(String name, String value) – add ServletContext initialization parameter to value.
withFilter(String name, Filter filter) – add filter in front of FacesServlet.
Additional configuration can be performed directly on the ApplicationServer instance, see JavaDoc for details.
Performing request
To perform JSF request, call environment.createFacesRequest(String url) method:
@Test
public void testRequest() throws Exception {
FacesRequest request = environment.createFacesRequest(“http://localhost/test.jsf”);
assertNotNull(request.execute());
String contentAsString = request.getConnection().getContentAsString();
assertTrue(contentAsString.contains(ResponseStateManager.VIEW_STATE_PARAM));
}
This method gets request URL and returns FacesRequest object, that allows additional configuration ( adding request parameters, cookies, headers ). The request is not active until start() or execute() methods callled. execute() method performs whole request cycle, while start() only initialized request, created FacesContext and returns, that allows test to execute Faces Lifecycle directly inside request context.
FacesRule
FacesRule is jUnit 4 MethodRule that invoked around every test method. It automatically configures and starts converter before method and shut down it after. Using method rule allows to combine with another rules ot test runners – jsf-test MockRunner, Mockito runner, parametrised tests. There is fragment of test that creates mock instances of Jsf beans and run facelets fragment with user registration form, using mock objects for ‘facade’ and ‘user’ beans:
@RunWith(MockitoJUnitRunner.class)
public class RegisterTest implements ServletRequestListener{
@Rule
public FacesRule rule = HtmlUnitRule.create().withResource(“/registerTest.xhtml”, “registerTest.xhtml”).withListener(this);
@Mock
Facade facade;
@Mock
User user;
@Before
public void setUp() throws Exception {
rule.setSessionAttribute(“facade”, facade);
}
public void requestInitialized(ServletRequestEvent sre) {
sre.getServletRequest().setAttribute(“user”, user);
}
registerTest.xhtml only includes registration form fragment by <ui:include> directive. Therefore, this test lets check functionality of the single fragment without having real EJB for facade, database, and without inference from other parts of application.
Leave a Reply