This lightweight library allows you to unit test Wicket pages easily: It launches Jetty to run your webapp in-process and launches the Selenium 2 web driver (can be headless, i.e., no browser needed). Then you can store POJO mock objects into the fields of your Wicket page and use the web driver to drive it.
The startup only takes a few seconds. If you run multiple tests together (as a test suite), the startup will occur only once, so it is pretty fast.
Major enhancements introduced in v3.0.1:
See the change log for more details.
In your pom.xml, add the dependency and the repository (the example below assumes that you're using TestNG. If you use JUnit, please see here):
<project ...> ... <dependencies> ... <dependency> <groupId>com.ttdev</groupId> <artifactId>wpt-core</artifactId> <version>3.0.1</version> <scope>test</scope> </dependency> <dependency> <groupId>com.ttdev</groupId> <artifactId>wpt-runtime</artifactId> <version>3.0.1</version> </dependency> <dependency> <groupId>org.testng</groupId> <artifactId>testng</artifactId> <version>5.13.1</version> </dependency> </dependencies> </project>
To allow injecting mock objects your Wicket pages, you need to install a global injector:
public class MyApp extends WebApplication { ... @Override protected void init() { MockableBeanInjector.installInjector(this, new MockableBeanInjector()); } }
In order to launch Jetty, your webapp and Selenium web driver automatically before your page tests, make sure you include the WebPageTestContext in your TestNG suite:
<suite name="wicket-page-test-sample"> <test verbose="2" name="tests" annotations="JDK"> <packages> <package name="..."></package> </packages> <classes> <class name="com.ttdev.wicketpagetest.WebPageTestContext"></class> </classes> </test> </suite>
Let's assume that your Wicket page is shown below. It is very simple: it uses a form to get some user input, perform some calculation and then outputs it as a result. The important point is that you should NOT have complex business logic in your Wicket page. Instead, encapsulate the logic into interfaces such as the MyService interface:
<html> <form wicket:id="form"> <input type="text" wicket:id="input"> <input type="submit" value="OK"> </form> Result: <span wicket:id="result" id="result">abc</span>. </html> public class PageContainingForm extends WebPage { private MyService service; private String input; private String result; public PageContainingForm(MyService s) { this.service = s; input = service.getDefaultInput(); Form<PageContainingForm> form = new Form<PageContainingForm>("form", new CompoundPropertyModel<PageContainingForm>(this)) { @Override protected void onSubmit() { result = service.getResult(input); } }; add(form); form.add(new TextField<String>("input")); add(new Label("result", new PropertyModel<String>(this, "result"))); } } public interface MyService { String getDefaultInput(); String getResult(String input); }
Create a TestNG test class. The key is to inject a mock object into the field named "service". The rest of the code will use Selenium to test drive the page:
@Test public class PageContainingFormTest { public void testSubmitForm() { // this is the mock object serving as MyService MyService mockService = new MyService() { public String getDefaultInput() { return "xyz"; } public String getResult(String input) { // simply double the input as the result return input + input; } }; // create a proxy around the mock object but that is serializable SerializableProxyFactory factory = new SerializableProxyFactory(); MyService proxyService = factory.createProxy(MyService.class, mockService); // get access to the Selenium web driver to control the browser WicketSelenium ws = WebPageTestContext.getWicketSelenium(); // open your page and pass the proxy as the constructor argument ws.openNonBookmarkablePage(PageContainingForm.class, proxyService); // check if the HTML element with attribute name="input" has a value of // "xyz" assert ws.getValue(By.name("input")).equals("xyz"); // tell the server side to include a marker cookie in the next page // response. This is needed only if the response page is same Wicket // page. If the response is another page, just try to locate the // element and Selenium will wait for it. ws.setResponsePageMarker(); // click the <input> HTML element whose attribute type="submit" ws.click(By.xpath("//input[@type='submit']")); // wait for the page with such a marker ws.waitForMarkedPage(); // check if the HTML element with attribute id="result" has the body // text "xyzxyz" assert ws.getText(By.id("result")).equals("xyzxyz"); } }
Add PageContainingFormTest to your TestNG test suite:
<suite name="wicket-page-test-sample"> <test verbose="2" name="tests" annotations="JDK"> <classes> <class name="com.ttdev.wicketpagetest.sample.plain.PageContainingFormTest"></class> <class name="com.ttdev.wicketpagetest.WebPageTestContext"></class> </classes> </test> </suite>
Set up Chrome
-Dcom.ttdev.wicketpagetest.webdriver.class=org.openqa.selenium.chrome.ChromeDriver -Dwebdriver.chrome.driver=c:\browser-drivers\chromedriver.exe
You should at least read:
For Spring users, read Spring support.
For Guice users, read Spring support.
For JUnit users, read JUnit support.
Lastly, there are:
To keep informed of updates, please subscribe to the announcement mailing list.