Preface
In the Test Driven Development mocking real objects is one of fundamental parts. For low-level JSF components and extensions development, having mocking framework environment is necessary for unit testing. Unfortunately, there are some problems:
- Most classes from JSF API not interfaces, but abstract and concrete classes. While modern mocking libraries, Mockito, jsf class extensions, and others, allows to mock concrete classes, all of them require some bytecode manipulation library to create mocks at runtime. For example, both Jboss Seam and EasyMock class extensions require different versions of javaassist library.
- Libraries like Apache Shale provide stub objects for JSF api, that not so convenient for testing, and none of them had JSF 2.0 version at the Richfaces 4.0 development time.
The idea behind jsf-mock project was similar to Easymock class extension library ( create subclasses for mocked objects that delegate calls to the EasyMock environment ), but, because we know which classes from JSF API should be wrapped, do it at compilation time and provide ready to use mock objects for tests.
Target environment
Jsf-mock objects can be used with:
- both Jsf 1.2 and 2.x, depends only from the jsf-api library used for tests.
- EasyMock 2.5.2 and late.
- Junit 3.x and 4.x, while we recommend to use Junit 4.8 and later for which we provide runners and method rules that takes care most of configuration jobs.
- TestNG.
Mock Generator Maven Plugin
All mock classes generated by the maven-mock-generator-plugin. This plugin intended for internal use to generate jsf-mock library, but can be also used to create mocks for custom JSF components. That plugin generates mock classes for all JSF objects and utility class that instantiates these objects.
Usage.
The simplest way to create mock objects for JSF is using FacesMock#createMock(Class toMock) method, or similar other from the FacesMock class. These methods have the same signatures and functionality as in the EasyMock class, but, if the class to mock beyond JSF API, it creates an instance of precompiled mock class. Otherwise, call will be delegated to corresponded EasyMock class.
There are some problem with JSF. Sometimes, it may be necessary to use FactoryFinder#findFactory or FacesConstect#getCurrentInstance static methods, that cannot be mocked.
FacesEnvironment
To solve that problem, jsf-mock project contains MockFacesEnvironment class that performs necessary configuration procedures. That class designed to use as internal field in the test class, and can be used with any test framework: Junit 3 and 4, or Testng.
Usage, with Junit 4.8:
private MockFacesEnvironment mockEnvironment;
@Before
public void setUp() throws Exception {
this.mockEnvironment = FacesMock.createMockEnvironment();
}
@After
public void tearDown() throws Exception {
// Necessary to clean up ThreadLocal variable in FacesContext.
mockEnvironment.release();
}
MockFacesEnvironment has a set of configuration methods ( having ‘with’ prefix ) that can be chained to describe requested features:
mockEnvironment.withServletRequest().withRenderKit();
Also, it contains the same set of create…Mock methods as FacesMock class. All mock objects created by environment can be resetted/replayed/verified by single call to environment instance.
Advanced usage, with Junit 4.x
Junit 4 introduced TestRunner feature that allows developer define its own extentions for test environment. Jsf-mock contains MockTestRunner class that simplifies working with mock objects:
- For fields in the test class and its superclasses, annotated by @Mock, @Strict, or @Stub annotations, it creates and injects ready to use mock object.
- It creates and initializes MockFacesEnvironment object, and injects it into field annotated with @Environment. Developer can describe requested environment features by annotation options. After a test, runner properly releases the environment.
- if field with type MockController exists in the test class, it injects controller instance there. That controller can be used to reset/replay/verify all mock objects created by the runner in the single method.
Mocking JSF view
Sometimes, it would be necessary to create not just mock component but fragment of JSF view. For example, to test UIData renderer, table component should contain columne and headers/footers. There is ViewBuilder class to do that:
ViewBuilder viewBuilder = ViewBuilder.createView().children(
ViewBuilder.component().id(“foo”),
ViewBuilder.component(UIInput.class).id(“input”)
).facets(
ViewBuilder.facet(“header”)
).setViewId(FOO_XML);
viewBuilder.replay();
Capturing ResponseWriter output
For custom renderers, it would be important to check generated html code. Faces-mocks allows developers to capture renderer output and analyse it with XPath-like criteria:
writer = new RecordingResponseWriter(“UTF-8″,”text/html”);
… call renderer to generate content
// verify output
assertEquals(“id1”,writer.find().element(“.*”).withAttribute(“id”).getAttribute(“id”));
MockFacesEnvironment creates capturing response writer if it requested by withResponseWriter() call, or Feature.RESPONSE_WRITER option in @Environment annotation.
Maven artifact for jsf-mock project available from Jboss Maven Repository, the source code repository on GitHub is git://github.com/alexsmirnov/jsf-test.git