Introduction

This little library allows you to unit test Wicket pages easily: It launches Jetty to run your webapp in-process and launches the Selenium client. Then you inject POJO mock objects into @SpringBean annotated fields (or @Inject if you use Guice) and use the Selenium client to drive your page.

Why is it useful?

  • The key benefit is that you can control the right thing (user input on the web page and the data your pages get, from the services), and then observe the right thing (HTML DOM elements, possible manipulated by Javascript/AJAX).
  • Your real application is run. You don't need to modify it in anyway.
  • It's very easy to implement as it relies on well established tools (Selenium and Jetty). It means it can easily be kept updated with new versions of Wicket.
  • It has special support for HTML pages generated by Wicket so that, e.g., you can wait for the completion of AJAX requests easily or locate an HTML element corresponding to a Wicket component easily.
  • Potentially this approach can be applied to frameworks other than Wicket.

How to use

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>1.6.1</version> <!-- Use 2.0.1 for Wicket 1.5.x-->
                        <scope>test</scope>
                </dependency>
                <dependency>
                        <groupId>com.ttdev</groupId>
                        <artifactId>wpt-runtime-spring</artifactId> 
                        <version>1.6.1</version> <!-- Use 2.0.1 for Wicket 1.5.x-->
                </dependency>
                <dependency>
                        <groupId>org.testng</groupId>
                        <artifactId>testng</artifactId>
                        <version>5.13.1</version>
                </dependency>
        </dependencies>
        ...
        <repositories>
                <repository>
                        <id>wpt-release</id>
                        <url>http://wicketpagetest.sourceforge.net/m2-repo/releases</url>
                </repository>
        </repositories>
</project>

To allow injecting mock objects in place of Spring beans, you need to install a special injector:

public class MyApp extends WebApplication {
        ...
        @Override
        protected void init() {
                MockableSpringBeanInjector.installInjector(this);
        }
}

In order to launch Jetty, your webapp and Selenium client 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>

Assume that your Wicket page is using a Spring bean as shown below (for Guice support, see here):

<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 Page1 extends WebPage {
        @SpringBean
        private MyService service;
        private String input;
        private String result;

        public Page1() {
                input = service.getDefaultInput();
                Form<Page1> form = new Form<Page1>("form",
                                new CompoundPropertyModel<Page1>(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 in place of a Spring bean into the field named "service". The rest of the code will use Selenium to test drive the page:

@Test
public class Page1Test {
        public void testSubmitForm() {
                MockableSpringBeanInjector.mockBean("service", new MyService() {

                        public String getDefaultInput() {
                                return "xyz";
                        }

                        public String getResult(String input) {
                                return input + input;
                        }

                });
                DefaultSelenium selenium = WebPageTestContext.getSelenium();
                WicketSelenium ws = new WicketSelenium(selenium);
                ws.openBookmarkablePage(Page1.class);
                assert selenium.getValue("input").equals("xyz");
                selenium.click("//input[@type='submit']");
                selenium.waitForPageToLoad("3000");
                assert selenium.getText("result").equals("xyzxyz");
        }

}

Install Selenium RC and run the Selenium server (and keep it that way during development).

Make sure that Tomcat (or any other web container) is NOT on your build path. This may be the case if you've configured the project as a dynamic web project in Eclipse. To remove Tomcat, right click the project and choose Build Path | Configure Build Path | Libraries.

Add Page1Test to your TestNG test suite and run that suite. If it doesn't work, post to our support forum or the Wicket user mailing list.

Going further

See here for more examples. See here for how to locate an HTML element corresponding to a Wicket component easily. See here for how to have Wicket Page Test launch the Selenium server automatically. See here for how to create mocks easily that will be resistant to changes to the service interface.

Keep informed of updates

To keep informed of updates, please subscribe to the announcement mailing list.