| Apache Wicket > Framework Documentation > Reference library > Testing > Testing Pages |
Here's a bit of what I've found out while writing tests for Wicket. The code is using Wicket 1.2 beta 3, but most of it should apply to 1.1.1 as well.
public class AppTester extends WicketTester { public AppTester() { super("/admin"); } public void initialize() { // not always called getSecuritySettings().setAuthorizationStrategy(new AdminAuthStrategy()); ServiceInitializer.initializeDevelopmentServices(); } protected ISessionFactory getSessionFactory() { return new AdminSessionFactory(this); } }
// e.g., Your TestCase -class private final static Method getReplaceModelMethod; static { try { getReplaceModelMethod = AttributeModifier.class.getDeclaredMethod("getReplaceModel"); getReplaceModelMethod.setAccessible(true); } catch (Exception e) { e.printStackTrace(); throw new RuntimeException(e); } } public void assertAttribute(String message, String expected, Component component, String attribute) { AttributeModifier behavior = getAttributeModifier(component, attribute); if (behavior != null) { try { IModel<?> model = (IModel<?>) getReplaceModelMethod.invoke(behavior); assertEquals(message, expected, model.getObject().toString()); return; } catch (Exception e) { throw new RuntimeException(e); } } fail("Attribute not found."); }
public void testRender() { // add some values directly to the database, to check the rendering (services are not flexible enough for me) // template here is a Spring JDBCTemplate, which is quite useful for running direct SQL queries without much red-tape template.execute( "update config set value='sampleuser' where name='userName';" + "update config set value='samplepass' where name='password';" + "update config set value='true' where name='allowOffsiteAccess';" + "update config set value='sampleiprange,anotherip' where name='trustedIPRange';" + "commit;"); // start the page - my page is package protected for better encapsulation, so I need an ITestPageSource // if the page takes parameters, just pass them to the constructor instead of setting them // through the database (that allows for better reuse) // [tester] here is an instance of my AppTester described above tester.startPage(new ITestPageSource() { public Page getTestPage() { return new ChangeOffSiteAccessPage(); } }); // check that the right page was rendered (no unexpected redirect or intercept) tester.assertRenderedPage(ChangeOffSiteAccessPage.class); // assert that there's no error message tester.assertNoErrorMessage(); // check that the right components are in the page tester.assertComponent("feedback", FeedbackPanel.class); tester.assertComponent("form", Form.class); // ok, now check not only that the component is present, but also that the model object // contains the correct value (was correctly bound) tester.assertComponent("form:username", TextField.class); final TextField usernameField = (TextField) tester.getComponentFromLastRenderedPage("form:username"); assertEquals("sampleuser", usernameField.getModelObject()); ... other components }
public void testInvalidLogin() { // create the form tester object, mapping to its wicket:id FormTester form = tester.newFormTester("form"); // set the parameters for each component in the form // notice that the name is relative to the form - so it's 'username', not 'form:username' as in assertComponent form.setValue("username", "test"); // unset value is empty string (wicket binds this to null, so careful if your setter does not expect nulls) form.setValue("password", ""); // slight pain in the butt, for RadioGroups the value string is a bit complicated // I believe it's the pageversion followed by the complete component name (not the relative, now) then the id for the choice itself // the easiest way is to render the page once and then copy & paste // pageversion didn't seem to have an effect, so I always replace it by 0 form.setValue("offSiteAccessEnabled", "0:form:offSiteAccessEnabled:Yes"); // another one to pay attention: listviews // here I have a 3 column iteration through a listview with 10 rows iterating through another listview // so it's the listview followed by the row id followed by the inner component in the listview form.setValue("addressRow:0:addressColumn:0:mask", ""); // all set, submit form.submit(); // check if the page is correct: in this case, I'm expecting an error to take me back to the same page tester.assertRenderedPage(ChangeOffSiteAccessPage.class); // check if the error message is the one expected (you should use wicket's internationalization for this) // if you're not expecting an error (testing for submit successful) use assertNoErrorMessage() instead tester.assertErrorMessages(new String[] { "A Login and Password are required to enable offsite access." }); }
public void testCancelLink() { tester.clickLink("form:cancelButton"); tester.assertRenderedPage(ChangeSystemParametersPage.class); ... clicked on cancel, verify that the data was not changed in any way } public void testGenerateQueryReport() throws UnsupportedEncodingException { // this one is a bit more interesting, as this page does a download-on-submit ... prepare the data for the test // prepare the form, fill the data, and submit final FormTester form = prepareFormTester(); form.setValue("dataType", "0:form:dataType:query"); form.submit(); // check that the submit created a download link final MockHttpServletResponse servletResponse = tester.getServletResponse(); // in this case it's a CSV report, so just convert the whole thing to a string final String report = new String(servletResponse.getBinaryContent(), servletResponse.getCharacterEncoding()); // compare it assertEquals("QUERY COUNT\n\n", report); }