Testing EJB3.0 Presentation at Parleys

December 17, 2009 Leave a comment

Szczecin JUG added to Parlays my presentation about Testing EJB3.0 (though the presentation should really be named: Testing and testing EJB3.0), that I was doing last year at Java4People conference in Szczecin, Poland.

Presentation is in polish language though, so don’t be surprised :). Presentation can be reached here.

Categories: Presentations

I wasn’t here for quite a while…

December 14, 2009 5 comments

I wasn’t here for quite a while… For the last three months I was quite busy since my life has changed rapidly. To tell the long story short:

1. First this thing happend:

2. Then we went there:

3. And then I’ve learned the consequences 🙂

Meanwhile I changed my job, did one commercial project using WicketCool (I will write about it soon) and I can finally get back to my blog ;). Hope to see you all soon.

Categories: News

Writing EVEN MORE readable and maintainable tests

August 25, 2009 2 comments

If you follow my blog you know that few weeks ago I posted an article about writing readable and maintainable tests. My understanding of readable and maintainable tests evolves in time, my views and opinions change and  thus my posts need update.

I thought that the easiest way to show you the changes will be an example. As before, examples are shown for Wicket application, however the rules can be applied to any other frontend frameworks (JSF applications can use for instance JSFUnit project). Secondly, if you haven’t read my article about readable and maintainable tests, I encourage you to do so, since this post is simply update of the previous one. Furthermore post about WicketTestBase should be helpful as well, since all examples inherit from WicketTestBase class.

But lets move on to our example. Imagine we are told to implement user story “Add new Applicant”.  General steps are as follows:

  1. User enters welcome page
  2. User clicks link called ‘create new applicant’
  3. User is given a form that he fills with Applicant data (name, surname and age)
  4. Users is presented with Applicants list, where newly added Applicant is visible
  5. Applicant is added to the Application he is applying to

Before I explain you all the  necessary details, please let me show you how would the final tests for this scenario look like. I want you to see them now, just to let you know how readable tests can really be. For the purpose of this  example I will only show two tests, however it should be obvious that in real life overall number of tests can be much bigger. The tests look as follow:

test #1  – Should show ApplicantsList after adding applicant

public void shouldShowApplicantsListAfterAddingApplicant
                  throws Exception {
 // given
 user.enters().welcomePage();
 user.clicks().createNewApplicationLink();

 // when
 user.fills().addApplicantForm("Adam", "Bauer", 27);
 user.clicks().saveAndExitButton();

 // then
 onpage.applicantsList.exists().isVisible().and().isOfType(ListView.class);
}

test #2 – Should show added applicant informations

public void shouldShowAddedApplicantInformations
                  throws Exception {
 // given
 user.enters().welcomePage();
 user.clicks().createNewApplicationLink();

 // when
 user.fills().addApplicantForm("Adam", "Bauer", 27);
 user.clicks().saveAndExitButton();

 // then
 onpage.applicantsList
            .containsElements(application.getApplicants());
 onpage.applicantsList
            .element(0, "appliocantName").isLabelWithValue("Adam");
 onpage.applicantsList
            .element(0, "appliocantSurname").isLabelWithValue("Bauer");
 onpage.applicantsList
            .element(0, "appliocantAge").isLabelWithValue("27");
}

Readable isn’t it? The tests themselves can be read as a normal sentences. They should give you this feeling that you are reading a book. This is what self-documenting code is all about. When you read the test, it is quite clear what the implementation should do. Test are understandable, test base is comprehensive. And you know what? It will still be, even after one year. Or maybe you are soon planning to hire new developer? Not a problem at all, he will easily understand them as well. That is what all the readability is all about!
Notice that in fact when reading those tests you are not even aware of the fact that they are testing Wicket application. Remember that tests should always represent the requirements! If those test fail and fixing them is not a matter of change in one or two lines of code, then it only means the requirements changed. However if the button gets different name or ApplicantsList suddenly gets different path, then fixing those tests is simply change in one line of code. This is what all the maintainability is all about!

The question remains then, what changes were applied. If you were asked to write similar tests and you would follow my previous guidelines, you would probably end up with something like this:

test #1 – Should show ApplicantsList after adding applicant

public void shouldShowApplicantsListAfterAddingApplicant
                  throws Exception {
 // given
 enterer.entersWelcomePage();
 clicker.clickCreateNewApplicationLink();

 // when
 formFiller.fillsAddApplicantForm("Adam", "Bauer", 27);
 clicker.clicksSaveAndExitButton();

 // then
 String pathToApplicantsList = "path:to:applicantslist";
 tester.getComponentFromLastRenderedPage(pathToApplicantsList);
 tester.assertVisible(pathToApplicantsList);
 tester.assertComponent(pathToApplicantsList, ListView.class);
}

test #2 – Should show added applicant informations

public void shouldShowAddedApplicantInformations
                  throws Exception {
 // given
 enterer.entersWelcomePage();
 clicker.clickCreateNewApplicationLink();

 // when
 formFiller.fillsAddApplicantForm("Adam", "Bauer", 27);
 clicker.clicksSaveAndExitButton();

 // then
 String pathToApplicantsList = "path:to:applicantslist";
 tester.assertListView(pathToApplicantsList, application.getApplicants());
 tester.assertLabel(pathToApplicantsList + "applicantName", "Adam");
 tester.assertLabel(pathToApplicantsList + "applicantSurname", "Bauer");
 tester.assertLabel(pathToApplicantsList + "applicantAge", "27");
}

It’s good already, but it has its flaws. First lets look at helper classes, they great at aggregating common actions (entering pages, clicking and form filling), but when we read the test

 (...)
 // given
 enterer.entersWelcomePage();
 clicker.clickCreateNewApplicationLink();

 // when
 formFiller.fillsAddApplicantForm("Adam", "Bauer", 27);
 clicker.clicksSaveAndExitButton();
(...)

it doesn’t sound right. Try to read above code out loud. If you do that, you will quickly learn that there is something missing. Lets try it, read this out loud:

“Enterer enters welcome page”
“Clicker clicks create new application link”
“FormFiller fills add applicant form”

What is wrong with it? Why doesn’t it sound right? Well we basically miss person who is responsible for all the clicking, entering and form filling. We miss here the User! Whenever I read test, I want to hear sentences like this:

User enters welcome page”
User clicks create new application link”
User fills add applicant form”

I mean who is this enterer, what is this clicker, were did this formFiller came from? It is User who does the whole work. Clicker, Enterer and FormFiller are just representations of the actions he does. Taking that fact into consideration I created another helper class called Userer.

public class Userer {

  private Clicker clicker;
  private Enterer enterer;
  private FormFiller formFiller;

  public Userer(Clicker clicker,
                Enterer enterer,
                FormFiller formFiller) {
      this.clicker = clicker;
      this.enterer = enterer;
      this.formFiller = formFiller;
  }

  public Clicker clicks() {
      return clicker;
  }

  public FormFiller fills() {
      return formFiller;
  }

  public Enterer enters() {
      return enterer;
  }
}

This class simply aggregates Clicker, FormFiller and Enterer. Userer becomes field in WicketTestBase (base class for all my Wicket tests) as shown below:

public class WicketTestBase {

    (...)
    protected Clicker clicker;
    protected Enterer enterer;
    protected FormFiller formFiller;

    protected Userer user;
    (...)

    private void initHelpers() {
        clicker = new Clicker(tester, enhancedTester);
        formFiller = new FormFiller(tester, enhancedTester);
        enterer = new Enterer(tester, enhancedTester, clicker, formFiller);
        user = new Userer(clicker, enterer, formFiller);
    }
    (...)

From now on you can use this ‘user’ field in your tests. Now we can refactor our test:

  1. calls to clicker become calls to user.clicks() e.g clicker.clicksSaveLink becomes user.clicks().saveLink() (notice we also changed clickSaveLink method name to saveLink)
  2. calls to formFiller become calls to user.fills() e.g formFiller.fillsAddApplicantForm(“Adam”, “Bauer”, 27) becomes user.fills().addApplicantForm(“Adam”, “Bauer”, 27)
  3. calls to enterer become calls to user.eneters() e.g enterer.entersWelcomePage() becomes users.enters.welcomePage()

Now our previous test will look like this:

test #1 – Should show ApplicantsList after adding applicant

public void shouldShowApplicantsListAfterAddingApplicant
                  throws Exception {
 // given
 user.enters().welcomePage();
 user.clicks().createNewApplicationLink();

 // when
 user.fills().addApplicantForm("Adam", "Bauer", 27);
 user.clicks().saveAndExitButton();

 // then
 String pathToApplicantsList = "path:to:applicantslist";
 tester.getComponentFromLastRenderedPage(pathToApplicantsList);
 tester.assertVisible(pathToApplicantsList);
 tester.assertComponent(pathToApplicantsList, ListView.class);
}

test #2 – Should show added applicant informations

public void shouldShowAddedApplicantInformations
                  throws Exception {
 // given
 user.enters().welcomePage();
 user.clicks().createNewApplicationLink();

 // when
 user.fills().addApplicantForm("Adam", "Bauer", 27);
 user.clicks().saveAndExitButton();

 // then
 String pathToApplicantsList = "path:to:applicantslist";
 tester.assertListView(pathToApplicantsList, application.getApplicants());
 tester.assertLabel(pathToApplicantsList + "applicantName", "Adam");
 tester.assertLabel(pathToApplicantsList + "applicantSurname", "Bauer");
 tester.assertLabel(pathToApplicantsList + "applicantAge", "27");
}

Pretty readable right? All looks good, but imagine what will happen, when path to ApplicationList change or it will become PropertyListView (instead of ListView)? Some time ago I realized that every action of the test scenarios falls into one of four categories. User either enters application, clicks a link or button, fills form with data or assert state of the application. For entering, filling and clicking I created helper classes that encapsulate those actions (Enterer, FormFiller and Clicker), however assertion still did not get its representation. Thus I created another helper class called Weberer.

public class Weber {

    // components
    public PageElement applicantsList;

    // testers
    private WicketTester tester;
    private EnhancedWicketTester enhancedWicketTester;

    public Weber(WicketTester tester,
                         EnhancedWicketTester enhancedWicketTester) {
        this.tester = tester;
        this.enhancedWicketTester = enhancedWicketTester;

        createPageElements(tester, enhancedWicketTester);
    }

    private void createPageElements(WicketTester tester,
                                    EnhancedWicketTester enhancedWicketTester) {
        applicantsList = new PageElement("applicationForm:panel:listApplicantsPanel:applicants",
                                         tester, enhancedWicketTester);
    }
}

This class represents informations presented on page and helps to perform various assertion actions on those objects. Weberer holds reference to public fields of type PageElement.

public class PageElement implements IPageElement {

    private final WicketTester tester;
    private final EnhancedWicketTester enhancedWicketTester;
    private final String path;

    public PageElement(String path, WicketTester tester, EnhancedWicketTester enhancedWicketTester) {
        this.tester = tester;
        this.enhancedWicketTester = enhancedWicketTester;
        this.path = path;
    }
    public PageElement exists() {
        tester.getComponentFromLastRenderedPage(path);
        return this;
    }

    public PageElement isVisible() {
        tester.assertVisible(path);
        return this;
    }

    (....)

Those fields represent different elements that can be found on page. So for example if suddenly you need to make some assertions on login form, then you will add to Weberer object new field:

public class Weber {

    // components
    public PageElement loginForm;
    (...)

    private void createPageElements(WicketTester tester,
                                                         EnhancedWicketTester enhancedWicketTester) {
        loginForm = new PageElement("path:to:login:form",
                                                            tester, enhancedWicketTester);
        (...)
    }

Since Weberer is also a filed in WicketTestBase class:

public class WicketTestBase {

    (...)
    protected Userer user;
    protected Weber onpage;
    (...)

you can access your newly created element directly from your tests:

   onpage.loginForm.exists();
   onpage.loginForm.isVisible();

When we apply those rules into our test, they will final look like this:

test #1 – Should show ApplicantsList after adding applicant

public void shouldShowApplicantsListAfterAddingApplicant
                  throws Exception {
 // given
 user.enters().welcomePage();
 user.clicks().createNewApplicationLink();

 // when
 user.fills().addApplicantForm("Adam", "Bauer", 27);
 user.clicks().saveAndExitButton();

 // then
 onpage.applicantsList.exists().isVisible().and().isOfType(ListView.class);
}

test #2 – Should show added applicant informations

public void shouldShowAddedApplicantInformations
                  throws Exception {
 // given
 user.enters().welcomePage();
 user.clicks().createNewApplicationLink();

 // when
 user.fills().addApplicantForm("Adam", "Bauer", 27);
 user.clicks().saveAndExitButton();

 // then
 onpage.applicantsList
            .containsElements(application.getApplicants());
 onpage.applicantsList
            .element(0, "appliocantName").isLabelWithValue("Adam");
 onpage.applicantsList
            .element(0, "appliocantSurname").isLabelWithValue("Bauer");
 onpage.applicantsList
            .element(0, "appliocantAge").isLabelWithValue("27");
}

The test code is now easy to read and easy to maintain. All the Wicket specific code is hidden behind those helper classes. This not only helps to maintain test in a short time (when for example path to some components change) but also in a long run (when for example API of the WicketTester change in the 1.5 version). It will be lot easier to apply those changes only to 5 helper classes, then to base of few hundred tests already implemented in your application.

All code presented here will be soon (in a matter of days) added to WicketCool project, so you will be able to see WicketTestBase in action.

WicketTestBase – base class for testing Wicket + Spring web applications

August 17, 2009 5 comments

When writing integration tests in Wicket, there are few initialization steps that need to be executed before actual testing:

  1. data initialization – tests often need static data in the database for each and every test method.
  2. tester initialization – tester is initialized with Application and Session object, given locale needs to be set, Spring injector needs to be pre-configured etc.
  3. helper class initialization

Putting those actions to some init method (annotated with @Before in JUnit) would be a good idea. However I thought that since those steps are done in every single test, smart thing to do is moving them up in class hierarchy into some super class.
This is how WicketTestBase was created. Base class for integration tests in Wicket + Spring applications. Let’s take a look at it:

public class WicketTestBase {

 @Autowired
 private ApplicationContext applicationContext;

 protected WicketTester tester;
 protected EnhancedWicketTester enhancedTester;
 protected Clicker clicker;
 protected Enterer enterer;
 protected FormFiller formFiller;
 (...)

WicketTestBase has six protected fields. Spring’s ApplicationContext is injected, other five fields (tester, enhanced tester and helper classes) need to be initialized for every test. All fields have protected access level,  thus they can be reached from test classes that will extend WicketTestBase.

If you haven’t heard about enhanced tester, then please follow this article. If Clicker, FormFiller and Enterer are new to you, then kindly check my article about readable tests.

public void init() {
 populateData();
 createTester();
 initHelpers();
}

Next we have the public init method. This method will be called with every test. Method populateData is empty by default, but can be extended in test classes inheriting from WicketTestBase.

 /**
  * Override to populate data in database
  * for each test
  */
 protected void populateData() {
     // override in test if necessary
 }

Method createTester is the most complex one, but still it should be clear what it does.

private void createTester() {
 tester = new WicketTester((WebApplication)
 applicationContext.getBean("wicketApplication"));
 tester.setupRequestAndResponse();
 tester.getWicketSession().setLocale(getLocale());
 tester.getApplication().addComponentInstantiationListener(
 new SpringComponentInjector(tester.getApplication(),
 applicationContext));
 enhancedTester = new EnhancedWicketTester(tester);
 initSessionBeforeTest((UserSession) tester.getWicketSession());
}

First WicketTester object is created with Wicket Application object as constructor’s parameter. Note that Wicket Application object is taken from Spring’s ApplicationContext. Then Spring pre-configuration takes place and at the end Enhanced WicketTester is created.

Note also that two hook methods are called: getLocale and initSessionBeforeTest.

/**
 * Override to change locale
 * @return locale, default EN
 */
 protected Locale getLocale() {
 return new Locale("EN");
 }

Method getLocale returns default local for the tests. By default it returns EN, but extending classes can override this method to provide different locale.

 /**
 * Insert application specific properties to session
 * @param session
 */
 protected void initSessionBeforeTest(UserSession session) {
 // override in test if necessary
 }

Method initSessionBeforeTest is empty by default. It should be overridden if you would like to insert any test specific data into session before each test.

At the end helper classes are initialized.

private void initHelpers() {
 clicker = new Clicker(tester, enhancedTester);
 formFiller = new FormFiller(tester, enhancedTester);
 enterer = new Enterer(tester, enhancedTester, clicker, formFiller);
}

And that is it. Below WicketTestBase in its full glory:

public class WicketTestBase {

 @Autowired
 private ApplicationContext applicationContext;

 protected WicketTester tester;
 protected EnhancedWicketTester enhancedTester;
 protected Clicker clicker;
 protected Enterer enterer;
 protected FormFiller formFiller;

 public void init() {
     populateData();
     createTester();
     initHelpers();
 }

 private void createTester() {
     tester = new WicketTester((WebApplication)
                        applicationContext.getBean("wicketApplication"));
     tester.setupRequestAndResponse();
     tester.getWicketSession().setLocale(getLocale());
     tester.getApplication().addComponentInstantiationListener(
                      new SpringComponentInjector(tester.getApplication(),
                      applicationContext));
     enhancedTester = new EnhancedWicketTester(tester);
      initSessionBeforeTest((UserSession) tester.getWicketSession());
 }

 private void initHelpers() {
    clicker = new Clicker(tester, enhancedTester);
    formFiller = new FormFiller(tester, enhancedTester);
    enterer = new Enterer(tester, enhancedTester, clicker, formFiller);
 }

 /**
  * Override to change locale
  * @return locale, default EN
  */
 protected Locale getLocale() {
     return new Locale("EN");
 }

 /**
  * Insert application specific properties to session
  * @param session
  */
  protected void initSessionBeforeTest(UserSession session) {
     // override in test if necessary
  }

 /**
  * Override to populate data in database
  * for each test
  */
 protected void populateData() {
     // override in test if necessary
 }
}

Simplest example of test extending from WicketTestBase will look like this:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {"classpath:testApplicationContext.xml"})
@Transactional
public class NameOfTheTest extends WicketTestBase {

    @Before
    public void init() {
        super.init();
    }

}

ContextConfiguration points to Spring’s configuration xml file (in this case testApplicationContext.xml) and Transactional annotation simply makes all test methods transactional. Worth mentioning is the fact that all this transactions are rolled back after each test method finish it’s execution, thus you won’t have to implement any destroyData method – this is automatically done for you.

Usage of WicketTestBase can be also found in WicketCool project. If interested, check it out.

see also:

  1. Writing readable and maintable integration tests (not only) in Wicket
  2. Test template you should always use
Categories: Wicket Tags: ,

Writing readable and maintainable integration tests (not only) in Wicket

August 12, 2009 6 comments

Enhanced WicketTester

August 5, 2009 6 comments

Headache Pill: Unable to find valid certification path to requested target

August 5, 2009 Leave a comment

Wicket testing pitfalls and API issues

August 3, 2009 1 comment

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
Categories: Wicket Tags: ,

WicketQuickstart archetype is not enough

July 26, 2009 2 comments

Wicket team gave us this maven archetype called wicket-archetype-quickstart, which generates simple wicket webapplication. You simply type in your console

mvn archetype:create
-DarchetypeGroupId=org.apache.wicket
-DarchetypeArtifactId=wicket-archetype-quickstart
-DarchetypeVersion=1.3.6
-DgroupId=com.mycompany
-DartifactId=myproject

and from now on you can explore the vast world of wicket development.  You get very simple maven project, with wicket Application object, WelcomePage (hello world type) and simple test that shows usage of WicketTester.

If you starting your adventure with Wicket, this should suffice. But as you get quickly through the wicket basics, you will quickly realize that wicket-archetype-quickstart is simply not enough. Eventually  you will finally decide to write your very first webapplication in Wicket and that will be the moment where wicket-archetype-quickstart will shows its weakness.

First of all, wicket-archetype-quickstart is simply webapplication project. There is no business layer, no persistence layer and simply no connection with some backend technology (for example Spring). Of course Wicket is only web framework, however nowadays I can’t simply imagine webapplication without some backend technology, so chances are, you will need one.

Wicket integrates with Spring rather smoothly. When configured, you will get out of the box:

  1. Dependency Injection
  2. Integration with JPA
  3. Open Session In View pattern [1]
  4. Transactional tests – one of advantages is fact that all action you made in tests on database are rolledback at the end of each test (regardless of whether test passed, failed or thrown an exception).

However to makes things work, you need proper configuration. Even for person experienced with Spring this task might be troublesome. Take for example dependency injection. You can inject dependencies that given controller needs, as you would do in any other Spring application. However in Wicket all controller fields are serialized with each request and they travel in cache with user session. If you would use @Autowired annotation, you could eventually serialized half of your application context.

Of course  Wicket team created @SpringBean annotation, that acts like @Autowired, but is free of just described  problems. Yet this proves that integrating Spring with Wicket might be a problem, even for someone exprienced with Spring. Not to mention a fact, that creating such integration (repetitively creating configurations for each new project) would be boring task, that would quickly end up in dull  copy-past from one project to another. I would really like to have some archetype that could do all this repetitive and boring actions for me.

Secondly, when creating wicket (+Spring+JPA) application from archetype, I would like to have it already grouped and organized by layers. One layer for domain area, one for business logic (service) area and one for the web part. Ideally I would have some examples that show how to use it. For instance an example that shows how to create dao object , use it as dependency in service object and finally use this service object in controller of my webapplication. This way I would not only have proper structure for my application, but also I would have examples of how to use it.

I belive that examples are very powerful. Whenever I try to use new technology I always go to the examples, try to run them and then I start extending them, while learning new technology at the same time. If examples are good, chances are I will learn how to use the technology in a proper way. In Wicket (+Spring+JPA) application it is easy for me to imagine a junior developer using DAO object in controller area. This is what I would call a bad programming, but if there were no given examples to show  good programming, I could not blame him.

Thirdly, Wicket gives robust security support, for both authorization and authentication. However you won’t find usage of it in wicket-archetype-quickstart. Since I’m almost always securing my webapplication and doing it is a simple copy-past from my older projects, why not put it in an archetype?

Last but not least are Wicket tests. They are powerful, but after few months of development in Wicket I believe that they need some conventions, otherwise  there might be a moment, when moving some component in markup tree from one place to another, will end up in failing 260 tests (paths will not match). You might find yourself in situation where you have to fix paths in 260 JUnit tests – and that is really not what you would like to be doing.

However there are ways and conventions that help dealing with this problem (where making this 260 tests passed is simply a matter of changes in 3 lines of code), however again examples are needed to show the usage of the convention.

There are few other things I would like to have in my Wicket Application archetype. Useage of CSS file and resourses for example is something that you will see in almost every webapplication. Configuration is simply matter of few lines in your code, but since it is repetitive, why not have it created automatically?

Well, I’m pretty curious what you think about it. Especially people that use Wicket. Do you also believe that wicket-archetype-quickstart is not enough? Currently I’m developing WicketCool project, one of its features will be extended maven archetype, that will try to solve described problems of wicket-archetype-quckstart. Can you think of any other things, that you would like to see in such archetype? What would enhanced your development by automating repetitive, configuration work? Let me know: leave a comment or contact me directly.

More information about WicketCool project soon to come. I can now tell you that the tool reached version 0.6.0-SNAPSHOT,  it can be downloaded from the project page (you no longer need to build by yourself) and  that I am still extending its functionality. However because I’m doing it by myself, tool develops rather slowly. Any volunteers happy to help, are more then welcome!.

[1]. If you don’t know what Open Session In View pattern is, then I strongly encourage you to google it. To tell the long story short, OSIV pattern helps you to deal with lazy initialized entities, whose values are somehow show to the user. EntityManager is closed after page response is rendered (not before), thus you don’t get LoadLazyException when reaching for entites in the controller.

Categories: Wicket Tags: ,

Back from Javarsovia2009

July 7, 2009 4 comments

Two weeks before Javarsovia were crazy as hell. Not only did I have to move out completely from my apartment (because of its total redecoration and all the dirty and messy work that are triggered because of that), but also make final preparations for my wedding to come (got only 2 months of freedom left 🙂 ), stay at work for 10-11 hours per day (deployment and small misunderstandings with the client) and in the meantime prepare for Javarsovia event. So to all people I was consistently ignoring and not replying emails and/or comments, I apologies, but I was busy. Really, really busy. I will do my best, not to make it happen again.

Back to Javarsovia. Despite the fact that I was actually finishing the presentation at 3 a.m. on Saturday, from what I can read on the web [1], I can count my presentation as a success. So I’m glad you all like it. To all the people who wanted to hear a little bit more then just basics – I’m sorry, it was planned, but there was simply no time (one hour is not enough:)).

Slides will be soon published on Javarsovia page, but I will also put them here on my blog, after translating them into English.

Few people asked me to finally publish THTemplate I presented. It is my pleasure to inform you that the template code is already on the web! I will make separate post about it, with more details, but for all eager who want to try it, here are few things you should know:

  • project finally got a name: Wicket Cool 🙂 (thus THTemplate is obsolete)
  • template I told about during presentation can be accessed by simply running

svn checkout http://wicketcool.googlecode.com/svn/trunk/wctemplate wicketcool-read-only

  • to create archetype simply do this:

svn checkout http://wicketcool.googlecode.com/svn/trunk/wctemplate wicketcool-read-only
cd wctemplate
mvn archetype:create-from-project -Darchetype.filteredExtensions=java

  • now to create your very own project, based on that arechtype, run below in your command line

mvn archetype:generate -Darchetype=wctemplate-archetype -DarchetypeCatalog=local -DgroupId=some-group-id-DartifactId=some-artefact-id -Dversion=some-version

And that should be it. You are ready to go. More about Wicket Cool project soon, but right now you can test drive the project template.

Out.

[1] Note that all of them are in Polish:

http://www.jakubiak.eu/2009/07/javarsowia-a-i-czy-i.html

http://koziolekweb.pl/2009/07/05/javarsovia-2009-juz-po/

http://pacykarz.blogspot.com/2009/07/sen-o-warszawie-javarsovia-2009.html

http://luksza.org/2009/07/06/javarsovia-09/

http://codehardgopro.blogspot.com/2009/07/javarsovia-2009-wrazenia.html

http://blog.kedziorski.pl/

http://marekklis.blogspot.com/

Categories: Presentations