Issue Reproduction & Debugging with RichFaces Framework Tests
June 9, 2013
When an issue is discovered in an real application, it needs to be reproduced by the dev team in a sandbox environment.
It really helps to have this reproducer in the form of an automated test that should work on a given sample code, but that is failing due to the underlying issue.
Such a test can be used for debugging the issue, leading into its assessment and resolution, and finally (once resolved) guarding against a regression.
This is exactly the use case for employing the Arquillian framework.
Sample Framework Test
Let’s look at the following integration test for FocusManager
taken from the RichFace’s source.
This test verifies that after a request the FocusManager
will enforce the focus of a particular input.
@Test public void when_there_is_form_based_focus_but_focus_was_enforced_using_FocusManager_then_it_is_not_aplied() { contextPath = URLUtils.buildUrl(contextPath, "form.jsf"); Warp.initiate(openPage).inspect(new VerifyFocusEnforcingOverridesFocusSettings("form:input2")); assertEquals(input2, getFocusedElement()); Warp.initiate(submit).inspect(new VerifyFocusEnforcingOverridesFocusSettings("form:input2")); assertEquals(input2, getFocusedElement()); Warp.initiate(ajax).inspect(new VerifyFocusEnforcingOverridesFocusSettings("form:input2")); assertEquals(input2, getFocusedElement()); }
In the external file, you can find a definition of Warp’s inspection which is suppose to verify which component is going to be focused after the request:
public class VerifyFocusEnforcingOverridesFocusSettings extends VerifyFocusEnforcing { private static final long serialVersionUID = 1L; /** * @param enforceFocusId clientId of input component to be enforced to gain focus */ public VerifyFocusEnforcingOverridesFocusSettings(String enforceFocusId) { super(enforceFocusId); } @AfterPhase(Phase.RENDER_RESPONSE) public void verify_focus_is_applied(@ArquillianResource FacesContext context) { AbstractFocus component = bean.getComponent(); FocusRendererBase renderer = bean.getRenderer(); assertFalse(renderer.shouldApply(context, component)); } }
Note that there is no mocking involved. We are using a real implementation in a real JSF context driven by a real browser.
The only missing piece here is the XHTML file we test - we define it right in the source, so the test and its sources are all in one place:
private static void addFormFocusIndexPage(FrameworkDeployment deployment) { FaceletAsset p = new FaceletAsset(); p.body("<h:form id='form'>"); p.body(" <r:focus id='focus' binding='#{componentBean.component}' />"); p.body(" <h:inputText id='input1' />"); p.body(" <h:inputText id='input2' />"); p.body(" <h:commandButton id='submit' value='Submit' />"); p.body(" <r:commandButton id='ajax' render='@form' value='Ajax' />"); p.body("</h:form>"); deployment.archive().addAsWebResource(p, "form.xhtml"); }
That is everything you need to reproduce the issue in automated way.
Authoring New Tests
When you write a test for reproduction you don’t even need to start on a green field, since a lot of components already have some tests and creating a specific reproducer is usually matter of copying & pasting with appropriate modifications to fit your new scenario.
The tests themselves can be written really easily since they reflect how we interact with a page in a browser (WebDriver API) and what the request causes on the server (Warp inspections).
Issue Assessment
RichFaces Framework tests even offers great tools for issue assessment so you can really quickly decide whether
-
is the issue a regression?
-
you can switch the test to use older RichFaces version
-
-
is the issue present in only a specific environment?
-
specific browser
-
Mojarra / MyFaces
-
By switching various maven profiles in the framework build and test execution, you can easily execute a test in different environments and effectively identify the root cause.
Conclusion
When you write a framework test you not only reproduce the issue, but you also help with issue assessment and investigation and finally provide code to verify that the component works as expected with any future changes.