Introduction

API draft

First idea

Using inheritance.

Example

The following class ExampleTestCase shows how a test case could look like with this new framework

@View(id = "test.xhtml", pageBeans = @PageBean(clazz = ExampleBean.class)) // this view will be accessed and the beans will be installed
@Dependency.List({
@Dependency(groupId = "javax.el", artifactId = "el-api", version = "2.2"), // for special dependencies
@Dependency(StandardDependency.EL_API_2_2) // for standard dependencies
})
@RunWith(WebappTestRunner.class)
public class ExampleTestCase extends WebappTestCase
{
@Inject
private ExampleBean exampleBean; // specified as PageBean, thus it is a valid resource
// NOTE that this ExampleBean instance will have to be a cglib proxy of the real bean class
// in order to allow the expected method call testing
public void testApplyInputValue()
{
// START first phase of test case: validating the view that "only" has been rendered
// NOTE that facesContext and root are from the first (=rendering) request at this time
assertNotNull(root.findComponent("fieldId"));
// END first phase
// START second phase of test case: setting values and clicking some button or link
input("test value").into("fieldId"); // set values using the clientId
click("buttonId"); // execute some action
// END second phase
// START third phase of test case: verifying the postback
// NOTE that facesContext and root are from the second (=postback) request at this time
assertThat(facesContext.getExternalContext().getRequestParameterMap().get("formId:fieldId")).is("test value");
assertThat(exampleBean.getInput()).is("test value").before(PhaseId.INVOKE_APPLICATION);
expectCall(exampleBean.action()).in(PhaseId.INVOKE_APPLICATION);
// for void methods:
exampleBean.actionListener(null);
expectLastCall().in(PhaseId.INVOKE_APPLICATION);
// END third phase
// now we could again set some input and click some button or link and do some other assertions...
}
}

Base Class

The base class for every test case will be WebappTestCase, which contains all necessary methods to set up the test case, to do assertions and to input data into fields and click buttons just like a user would do. These methods will use a fluent API approach to ease usage. Furthermore any configuration will happen via annotations and resources will be injected using the @Inject annotation from javax.inject.

Preconfigured base classes

Because of the fact that WebappTestCase will read the configuration annotations from all its super classes (stopping by itself), it is very easy to create preconfigured test cases e.g. for extension testing. ExtensionTestCase shows an example.

Second idea

Using separate configuration classes and an annotation to bind a config to a test class and also some helper classes instead of inheritance.

Example

The following class ExampleTestCase shows how a test case could look like with this new framework (second idea)

@View(id = "test.xhtml", pageBeans = @PageBean(clazz = ExampleBean.class)) // this view will be accessed and the beans will be installed
@Configuration(SomeConfiguration.class) // the configuration class contains the Dependencies
@RunWith(WebappTestRunner.class)
public class ExampleTestCase
{
@Inject
private ExampleBean exampleBean; // specified as PageBean, thus it is a valid resource
// NOTE that this ExampleBean instance will have to be a cglib proxy of the real bean class
// in order to allow the expected method call testing
@Inject
private WebappTester tester; // will provide all necessary methods to control the test case
public void testApplyInputValue()
{
// START first phase of test case: validating the view that "only" has been rendered
// NOTE that facesContext and root are from the first (=rendering) request at this time
tester.assertNotNull(root.findComponent("fieldId"));
// END first phase
// START second phase of test case: setting values and clicking some button or link
tester.input("test value").into("fieldId"); // set values using the clientId
tester.click("buttonId"); // execute some action
// END second phase
// START third phase of test case: verifying the postback
// NOTE that facesContext and root are from the second (=postback) request at this time
tester.assertThat(facesContext.getExternalContext().getRequestParameterMap().get("formId:fieldId")).is("test value");
tester.assertThat(exampleBean.getInput()).is("test value").before(PhaseId.INVOKE_APPLICATION);
tester.expectCall(exampleBean.action()).in(PhaseId.INVOKE_APPLICATION);
// for void methods:
exampleBean.actionListener(null);
tester.expectLastCall().in(PhaseId.INVOKE_APPLICATION);
// END third phase
// now we could again set some input and click some button or link and do some other assertions...
}
}

Base Class

There will be no base class for this idea, but some Configuration classes and a WebappTester to provide the needed functionality (from the superclass of the first idea).

Preconfigured base classes

As there are no base classes, configuration classes will be used instead. However, there's no reason why a pre-configured base class couldn't be created which delegates calls to the helper classes.

Configuration

The framework uses a config class to get configuration options like the JSF implementation (MyFaces or Mojarra) and the related version of it. These configuration options will have standard values and will be configurable via System properties (which are very easy to set using maven).