The JSFServerSession Class
JSFUnit's JSFServerSession provides access to server-side objects needed to examine the entire state of a JSF application.
To see the full javadoc for this class, click here.
Getting a JSFServerSession
You get a JSFServerSession from the JSFSession object. You create the JSFSession object by passing a partial JSF URL into the constructor. This causes a real HTTP request to be sent to your JSF application. After that, you can examine the full server-side state of your application.
JSFSession jsfSession = new JSFSession("/mypage.jsf"); JSFServerSession server = jsfSession.getJSFServerSession();
Note that the above URL needs to be a JSF URL that corresponds to how your FacesServlet is mapped. It could also be something like "/mypage.faces". If your FacesServlet is path-mapped then the URL would be something like "/faces/mypage.jsp".
FacesContext Access
The key to all of JSFUnit is that it gives your test access to the FacesContext. In production, the last thing that happens at the end of the JSF lifecycle is to destroy the FacesContext. But with JSFUnit, the FacesContext is preserved and bound to the thread of your JUnit test. This gives you access to all per-request and per-application state. In your test, you have two ways of getting the FacesContext. Most JSF developers will recognize the first way:
FacesContext ctx = FacesContext.getCurrentInstance();
The second way to get it is through the JSFServerSession object:
FacesContext ctx = server.getFacesContext();
With a handle to the FacesContext, you can test almost anything you would want to know about on the server side. A few are highlighted below along with some JSFServerSession convenience methods that make testing a bit easier.
Testing Navigation
A unique feature of JSFUnit is that it gives you the ability to test your navigation rules by simply asserting that a client request resulted in the expected JSF view. We do this with the JSFServerSession.getCurrentViewID() method.
client.setParameter("myInput", "myValue"); client.submit(); assertEquals("/expectedView.xhtml", server.getCurrentViewID());
Testing Managed Beans
Another common test is to check that managed beans were properly updated. This is done with the JSFServerSession.getManagedBeanValue() method, passing in a simple EL expression.
assertEquals("Stan Silvert", server.getManagedBeanValue("#{employee.name}");
If you need to access managed beans in Seam conversation scope, you need to use the special "seamconversation" identifier in your EL expression. This identifier only works in JSFUnit tests.
Hotel hotel = (Hotel)server.getManagedBeanValue("#{seamconversation.hotel}"); assertEquals("Hilton Diagonal Mar", hotel.getName());
Testing the Component Tree
Each JSF request creates a tree containing all components in the view. The component view is a tree of java objects that is independent of the HTML sent to the client. Testing the component tree is often superior to testing the client-side HTML because:
It's much easier as you can make simple JSF API calls instead of checking raw text or the contents of the client-side DOM.
You don't have to rewrite your test when the HTML changes.
You can validate components where rendered=false. In this case, the component is not rendered on the client side, but still has state on the server side.
To get the root of the tree, you get a handle to the UIViewRoot like this:
UIViewRoot root = server.getFacesContext().getViewRoot();
However, the JSFServerSession has two convenience methods for common component tree operations. These are findComponent() and getComponentValue(). Each takes a component ID as an argument. Click here for a discussion of using the component ID with JSFUnit..
If I want the component's value, I just use getComponentValue()
JSF Page:
<h:inputText id="theBirthday" value="#{person.birthday}" rendered="#{person.prefs.displayBirthday}"> <f:convertDateTime></f:convertDateTime> </h:inputText>
JSFUnit code:
Date birthday = (Date)server.getComponentValue("theBirthday");
If I want to get the component instance itself, I use findComponent(). In this example we want to test that the birthday field is displayed for this use case:
UIComponent theBirthDay = server.findComponent("theBirthday"); assertTrue(theBirthDay.isRendered());
Note that you can also use the JSF API to find components like this:
UIComponent theBirthDay = server.getFacesContext().getViewRoot().findComponent("formID:theBirthday");
However, the rules for the search argument are much more complicated. Click here for details.
Testing with ExternalContext
The ExternalContext provides information about the application's external environment. You access it through the FacesContext like this:
ExternalContext extContext = server.getFacesContext().getExternalContext();
When you get the ExternalContext in JSFUnit code as above, you are getting an instance of JSFUnitExternalContext. The reason this is needed is because after a JSF request is over, the servlet container recycles objects like the HttpRequest and HttpResponse. The JSFUnitExternalContext preserves as much of the request state as possible, and most ExternalContext methods work without issues. However, you should be careful to check the javadoc for JSFUnitExternalContext before using it.
Testing Error Messages
Consider a JSF component with validation:
<h:inputText value="#{foo.text}" id="input_foo_text"> <f:validateLength minimum="2"></f:validateLength> </h:inputText> <h:message for="input_foo_text" styleClass="errorMessage"></h:message>
If you want to get all the error messages for the entire page, you would say:
Iterator<FacesMessage> allMessages= server.getFacesMessages();
If you just want to get the error messages associated with the single input component, just pass in its component ID:
Iterator<FacesMessage> fooInputMessages = server.getFacesMessages("input_foo_text");
Comments