Home > Wicket > Wicket testing pitfalls and API issues

Wicket testing pitfalls and API issues

WicketTester is so cool

WicketTester is a very powerful tool.  It gives ability to easily write robust and accurate integration tests and in my opinion makes Apache Wicket (with combination of some backend technology like Spring) the best framework on the market for TDD development. And I strongly stand for what I just said. I just simply know that from my very own experience:  currently ~90% of requirements in my recent Wicket project were developed using TDD practice.

WicketTester is not that cool

However despite all that, there is another side to that story. WicketTester is not a first class citizen in Apache Wicket framework. Even its developers agrees that “currently WicketTester is one of the less mature parts of the core project”.  And I’m not talking about its inner implementation, because as an end user, my real concern are two things: does it work correctly and does it has readable API (which will make my tests readable)? Unfortunately, for WicketTester, that is not always the case. Let me show you why.

1. Pitfalls

1.1 Invisible and disabled forms

Let’s say that for example you have a sign-in form, and you are writing a test for it. The use case is rather simple:  we enter sing-in page, fill login field with value “admin” and after submitting  form, UserSession object should hold reference to the User object with login “admin”.

@Test
public void shouldLogInAdminUser()
             throws Exception {
 // given
 enterer.enterSigninPage();

 // when
 FormTester formTester = tester.newFormTester("siginForm");
 formTester.setValue("login", "admin");
 formTester.submit("signInButton");

 // then
 assertEquals("admin",
              UserSession.get().getUser().getLogin());
}

Looks rather ok, ain’t it? But what you think would happen, if TextField “login” was invisible at that moment? For me, obvious behavior would be some sort of exception on line 09, setting the value to invisible component is impossible in real life, thus it should be impossible in test. Unfortunately the tests goes on without any warning and fails on line 13. Because login field was invisible, setting User.login value to “admin” didn’t occur and so the User was never added to the UserSession.

Now if you think, this is very trivial scenario, try to imagine what would you do, if situation like this happened in your code. You have written test, checking whether admin user is logged in with value “admin”, but the test fails on assertion. I guarantee that the first thing you do,  would be checking the sign-in logic.  It takes time and some debugging to realize that login field was simply invisible. Method setValue did not perform any action, but also did not raise any exception.  Finding this sort of bug would take some time for this simple scenario, but believe me, it can be long and frustrating when dealing with it for the first time, on page with large form, divided and organized on different panels.

Note also that this situation will also occur, if the whole Form class object is invisible. What makes it even worse is the fact, that invisibility is not the only issue. If your form would be disabled or had disabled fields, tests will act in same way. They won’t raise exceptions, but they won’t set values either.

1.2 Setting selectable

Imagine that on the sign-in page long time ago you entered another TextField called ‘select’. You even wrote a test for it.

@Test
public void shouldReadSelectField() throws Exception {

 // given
 enterer.enterSigninPage();

 // when
 FormTester formTester = tester.newFormTester("siginForm");
 formTester.setValue("select", "somevalue");
 formTester.submit("signInButton");

 // then
 // some assertions here

}

But after a while some other developer decided that ‘select’ should not be TextField but DropDownChoice. He made preferable changes in implementation, however he totally forgot about tests (I know, ignorant! ;)). Nevertheless you should not be worried, right? I mean, some sort of exception should be thrown at line 09, since method select() should be used, not setValue. Again however, no such exception occurs.

Method setValue itself is not doing anything (since it is not possible to setValue to the DropDownChoice). Given test would fail or not (depending on the assertions), but still it could take some time to figure out what happened.

1.3 I’m a SubmitLink you moran!

Another scenario is when you have some sort of Link object. Let’s say that the link is on WelcomePage and should redirect to SignInPage. As usual you implement logic in onClick() method, simple setResponse(SignInPage.class) will suffice. The test for this scenario could look like this.

@Test
public void shouldKnowWhenDealingWithSubmitLinkNotLink()
          throws Exception {
 // given
 enterer.enterWelcomePage();

 // when
 tester.clickLink("signinLink");

 // then
 tester.assertRenderedPage(SignInPage.class);
}

But what would happen if someone changed the Link into SubmitLink? For the moment you might think, that there should not be any problem since SubmitLink extends Link class. However notice that chances are, that switching from Link to SubmitLink would probably  trigger movement logic from onClick() method to onSubmit() method.

This way tester.clickLink() will click the link, but no action will happen, since all the logic will be moved out from the onClick method. The test in almost most cases will fail. In this trivial example, it should be rather easy to find out why, but if you have a little bit larger test, were clicking the link is not the action that is being tested (links are just being clicked to reach to some state of application), then finding out why suddenly test fails can take few moments.

1.4. Wicket 1.3.x problems

Some issues present in 1.3.x release of the Wicket framework, where fortunately fixed in the 1.4 branch. Since recent release of Wicket 1.4, below described problems might be soon obsolete. Nevertheless it will take some time, for all Wicket project to switch from 1.3.x to 1.4 version, thus I will try to briefly describe them.

setting not existing TextField

Lets go back to our first example:

@Test
public void shouldLogInAdminUser()
             throws Exception {
 // given
 enterer.enterSigninPage();

 // when
 FormTester formTester = tester.newFormTester("siginForm");
 formTester.setValue("lgin", "admin");
 formTester.submit("signInButton");

 // then
 assertEquals("admin",
              UserSession.get().getUser().getLogin());
}

Notice that on line 09 I made a typo, name of the field should be “login” not “lgin”. Expecting Exception thrown at this point my friend? This won’t happen! Test simply goes on, without any warning, but field is never filled with value. Issue fixed in 1.4 branch, throwing appropriate exception at line 09.

clicking not existing Button
@Test
public void shouldLogInAdminUser()
             throws Exception {
 // given
 enterer.enterSigninPage();

 // when
 FormTester formTester = tester.newFormTester("siginForm");
 formTester.setValue("login", "admin");
 formTester.submit("sgnInButton");

 // then
 assertEquals("admin",
              UserSession.get().getUser().getLogin());
}

Same thing will happen if you have typo in your submit button (here on line 10). Button is never clicked, since it does not exist, but no exception is thrown either. Again issue was fixed in branch 1.4.

2. API issues

2.1 Clicking link, clicking AJAX link

Imagine you are seeing Wicket test for the very first time in your life. You’ve never programmed in Wicket before and yet someone gives you test, that contains this line of code:

 tester.clickLink("adminPageLink");

Pretty straightforward, right? One can clearly see that we are clicking adminPageLink. But imagine that later on, you see this:

 tester.clickLink("openSubPanelLink", true);

Ok, we are clicking openSubPanelLink, but what does second, boolean parameter means? One have to look up documentation to realize that we are clicking link in AJAX manner. But honestly, would not be much simpler  and more readable to just call

 tester.clickAjaxLink("openSubPanelLink");

Method clickAjaxLink could even do some validation, checking whether link that is being clicked, is of AJAX type.

2.2 Assert enable, assert disable

WicketTester gives this assert methods like assertVisible, assertInvisible. What really strikes me is lack of methods such as assertEnabled and assertDisabled. I mean, lots of my components are visible or hidden in my application and my tests need to check that, but I also have a lot of fields that are being enabled and disabled. Why not then assertEnabled and assertDisabled? Strange but I need to cope with that.

Summery

To sum up, I love WicketTester. Without it my productivity in Wicket would be much much lower. Described pitfalls and API issues are what I learned from my 5 months experience with Wicket. Pitfalls were source of few hours of debugging, I hope with this post, you won’t have to waste your time on them.

You might also want to read about:

  1. Enhanced WicketTester
Advertisements
Categories: Wicket Tags: ,
  1. No comments yet.
  1. August 5, 2009 at 10:03 pm

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: