h1

Writing EVEN MORE readable and maintainable tests

August 25, 2009

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.

h1

WicketTestBase – base class for testing Wicket + Spring web applications

August 17, 2009

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
h1

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

August 12, 2009

As you probably already know I do a lot of integration tests while developing applications in Wicket. In fact, I write  so many tests that I quickly learned  that writing the test itself is the easy part. Maintaining them is a whole other story.

key word #1: readability

The question you should always ask yourself when writing a test is “Will I understand this test in a future?” or even better “Will colleagues from my development team understand it today?”. Test becomes useless when you don’t understand what it is doing.  If you can’t understand it then in most cases it simply means that test is unreadable.  Reading tests should be easy as reading a book. All this might seem obvious for you but believe me it isn’t for everyone. I’ve seen developers stunned and confused when looking at their own test, that they wrote few months before. If you can’t understand the test, you don’t know what the test is doing, you have absolutely no idea what part of code it is testing. At that point test is useless, you can easily delete it. Honestly, you won’t need it.

The only reason to have a test in your project in the first place, is to be able to cope with changes in a quick and robust way. If I wrote some application and I knew that in a future no single line in it will ever change, I wouldn’t write test for it. Really? Ya, really!  I would simply click through all the requirements, check that they all are implemented and leave the application as it is. But stuff like this never happen. Code will change eventually. Requirements will change and so will the implementation. Tests give you feedback, they make you “brave” just enough to deal with those changes. But if you don’t understand your own tests, you won’t be able to deal with them. Imagine that you wrote some additional functionality in your project, that broke some tests. If you can read your test and fully understand them, then you can quickly find reason why the test failed and make needed changes (in implementation or in test itself). With unreadable test you will spend quite some figuring out what the failing test is actually doing, before you start applying needed changes. It is worth mentioning it again:  The only reason to have a test in your project in the first place, is to be able to cope with changes in a quick and robust way. With unreadable tests you loose the ‘quick’ part of this sentence.

You truly profit from readability during the whole project. Coping with changes is only top of the iceberg. What you also get is time and peace.  If someone ask you “Can you please explain me how the controller you wrote works”, you can refer this person to your test base. If this person can read your tests like a book, then he will never again bother you with those kind of questions.

In ideal world when your development team gets new developer,  the first task he should do,  is reading application tests. There is no better way to understand the requirements of the application and how those requirements were implemented, then just reading tests. You can spend quite some time explaining usage of the IOFileManager class you wrote 8 months ago, but if you have tests for it, you won’t have to do it. The test will do it for you. Yet again, to make it work, you need to have your tests readable.

key word #2: maintainability

From time to time the requirements will change. Remember that tests should mirror the requirements. Thus changing the requirement might (it probably even should!) break some tests. In most cases you only need to fix one or two lines of code in the test to make it “green” again. But when you have more then few hundred tests in your project, this might get ugly. You change the implementaion of the requirement a little bit and suddenly 32 test fails. Fixing one line of code in each test would be frustrating, time consuming and made you eventually hate writing tests. That is why it is quite important to write test in such way, that maintaining them is an easy job. You really would like to be in a project, where making those 32 failing tests “green” again is really matter of changing 3 lines of code all together.

Coping with hundreds of tests – Wicket example

Examples shown here are written for web application created with Apache Wicket framework. Beside the fact that I’ve been ranting from time to time about WicketTester, I still believe that it is one of the best frameworks on the market for TDD development. Nevertheless below described ideas can be easily adopted to whatever frontend framework you are using. For JSF developers I recommend JSFUnit project. However I encourage you to give Wicket a try, you might be amazed with experience.

Ok, so back to main topic, let’s see how it can be done in Wicket. Check out below this very simple test written for class CreateApplicationPage:

@Test
public void saveButtonVisibility()
                              throws Exception {

WicketTester tester = new WicketTester();
tester.startPage(WelcomePage.class);
tester.assertRenderedPage(WelcomePage.class);
tester.clickLink("openc4ps:0:openc4ps-link",true);
tester.clickLink("c4p:create-application-link");
FormTester formtester =
            tester.newFormTester("applicationForm");
formtester.submit("button.save.and.exit");
tester.clickLink("openapps:0:openapps-link");

tester.assertInvisible("applicationForm:button.save");
}

Right now, I know exactly what this code is doing. But do you? Or even worse, will I understand it in 6 months time? Let’s try to look at it together. You can see that the test starts at WelcomePage. But then  some link is clicked in ajax way. What are “openc4ps” you don’t know? Where “openc4ps-link” leads to is a mystery as well. Then probably application is created. I say probably because we click “create-application-link”. Then we save and exit. And then save button is invisible. Ohhh, that’s right, we now clearly see that test was testing whether save button will be invisible. To bad we learn it at the end.

Tests like this one I call unreadable. You have to go back to the implementation, read it carefully to understand how it works. After that you can go back to the test itself. These kinds of tests are only understand fully by their creators only, who will also eventually forget what the test were doing. Those test might cover requirements, they might deal with the very core of the application, but still they are pain.

But check out the same tests written a little bit differently:

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

// when
clicker.clickCallForPropsalFromMenu(0);
clicker.clickCreateNewApplication();
clicker.clickSaveAndExitButton();
clicker.clickOpenApplication(0);

// then
tester.assertInvisible("applicationForm:button.save");
}

We first start reading method name and we quickly learn that the class we are testing (CreateApplicationPage) ‘should hide save button in view mode‘. This is the simplest case of self documenting code. Nice isn’t it? I am using here genius  “given-when-then” test template taken from BDD world. If you are interested why you ought to name your tests with “should” prefix and why divide them into given – when – then sections, then please read my article about it.

Ok, but back to our test.  The code above is taken from project I am currently working on. This is not something created for this post only. This is real test from existing project. However chances are that you probably are not part of my development team. You don’t know what Call For Proposal is or what object Application represents, since this terms are domain specific. Yet still while reading this test, it should be clear to you that given you are on welcome page of the application, when selecting first call for proposal from the menu, creating new application, saving it and then opening it again, then save button should not be visible.

Why this small trick boots readability, should be clear to you by now.  All the detailed WicketTester specific code is hidden behind more readable methods. The question you might still ask yourself is why this enhance maintainability of the test code? What are those clickers, enterers etc.?

When I started writing integration tests for the project I’m currently working on, I realized  that every action of the test scenarios falls into one of four categories. I either enter application for given url, click a link or button, fill form with data or assert state of the application. Because those actions started to repeat them-self in lots of tests, I encapsulated them in helper classes: Enterer, Clicker and FormFiller.

  1. Enterer holds all the methods responsible for entering the application. They are the starting point of each test. Normally I call one method of the Enterer at the beginning of each test.
  2. Clicker encapsulates all actions that click links or buttons (especially if the button is acting more like a link then button that is submitting the form). Methods like clickCreateApplicationLink(), clickSaveButton(), clickDeleteActionLink() etc.
  3. FormFiller is responsible for filling and submitting form. If for example you are on LogInPage, then you can call in your test method formFiller.fillAndLogLoginForm(“login”,”password”). The method will fill the fields for you and click login button.

Why this makes it more maintainable? First of all imagine, that some link suddenly becomes a button. Or a form is suddenly closed inside WebMarkupContainer. Your test will fail because of it, but to make them back to normal, you only need to change on or two lines of code in your helper classes. Secondly, code can be easily reused. If I wrote a method entereWelcomePage() in Enterer helper class, then other developer can use it as well. Right now before I create any new method in a helper class, I first check whether it was not created before.

Three helper classes, but they make wonders. Trust me! And if you dont believe me, try it yourself. I gurentee you won’t stop using it once you start. It is addictive. I started using helper classes four months ago. Now everyone in my team are using them :)

See also:

  1. Test template you should always use
h1

WicketCool looks for Windows testers

August 8, 2009

WicketCool is continuing its march towards stable release 1.0.0, currently I am really close in finishing version 0.6.0. As I try to keep this code as much tested as possible, there might be still some bugs and issues on integration level, especially in Windows environment. I currently have one system installed on my computer and that is Linux Kubuntu. Because of that it is kind of impossible to fully test WicketCool whether it is running correctly on Windows machine.

And that is why I am looking for someone ready to participate in WicketCool project in role of ‘Windows tester’. In other words someone who would from time to time download latest snapshot of the WicketCool, run its core functionalities and check if they work correctly. So, are there any volunteers?

h1

Enhanced WicketTester

August 5, 2009

Recently I wrote about pitfalls and API issues in WicketTester. For me personally, described problems are real problem. I write a lot of test during development and I need to have notion that the tool I’m using is error free.  That if assertion fails in my test, then it can only means there is a bug in my implementation, not in my test (because for example I made a typo when calling submit button in my test). Nothing can be more frustrating when you realize after some time of debugging, that your test is failing not because your logic is incorrect, but because WicketTester did not inform you that you are reaching for not existing component.

To solve the problems that raised, I created Enhanced WicketTester. This tool will not only make your tests more robust, but will also improve their readability.

To use use Enhanced WicketTester, you have to instantiated it with normal WicketTester as a parameter:

WicketTester tester = new WicketTester();
EnhancedWicketTester enhanced =
             new EnhancedWicketTester(tester);

For clicking on links, you currently got three methods:

enhanced.clickLink("link");
enhanced.clickAjaxLink("ajaxLink");
enhanced.clickSubmitLink("formPath","submitLink");

Before doing the actual clicking, those methods will not only check if given links exist and are visible, but also if they are of a given type.

Also with Enhance WicketTester you can now check whether  any of your components is disabled or enabled.

enhanced.assertEnabled("path");
enhanced.assertDisabled("path");

Worth noticing is fact, that Enhanced WicketTester gives you slightly changed API for form filling. Imagine for example that you want to fill given form with values:

<form wicket:id="loginForm">
  Login: <input wicket:id="login" />
  Password: <input wicket:id="password" />
  Time zone:
<select wicket:id="timezone" />
  <input type="button" value="Log in"                       wicket:id="loginButton" />
</form>

Doing it in Enhaned WicketTester would look like this:

enhanced.form("loginForm")
     .setTextFieldValue("login", "admin")
     .setPasswordTextFieldValue("password", "pass")
     .selectDropDownChoice("timezone", 1)
     .submitWithButton("loginButton");

Enhanced WicketTester not only will check whether all given components exists, but also if the are visible and enabled. Explicitly telling that you are setting TextField (method setTextFieldValue) and not for example TextArea (method setTextAreaValue) makes your test even more type-safe and therefore robust.

So the question remains, how to use Enhance WicketTester in your project? If you are Maven user, all you need to do is add following line to your pom.xml, in dependencies section:

<dependency>
  <groupId>pl.rabbitsoftware</groupId>
  <artifactId>enhancedwickettester</artifactId>
  <version>1.0.0</version>
  <scope>test</scope>
</dependency>

Also make your project aware of Enhanced WicketTester maven repository, by adding at the end of your pom.xml repository information:

<repositories>
  <repository>
    <id>enhancedwickettester</id>
    <url>http://enhancedwickettester.googlecode.com/svn/repo</url>
  </repository>
</repositories>

If you don’t use maven, then simply visit project official site, download jar file and add it to your classpath.

h1

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

August 5, 2009

If you are connecting to web service over https (in other words using SSL) you might encounter well known exception

javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target

It means that you are connecting to service over SSL, yet you don’t know or don’t accept authorization certificate of that service. This is something you are very familiar with, even if you don’t think you are. Whenever you are trying to connect to the  server using your web browser (any adrress with https:// in it), a window would pop-up informing you, that connection cannot be established, because (quoting Firefox) “certificate is not trusted, because certificate’s publisher is not trusted”. You then click “Trust this website” or “Accept security exception” and you can surf   freely through the website using safe SSL connection.

In case of Java programs, there is no certainty that on the other side there always will be user, able to click “Accept security exception”. That’s why, to give your application ability to connect over SSL, you need to have it properly configured, so it can always automatically accept this “security exception”.

To do it, you generate keystore for given certificate and then use that keystore in your application. Below short instruction how to do it:

1. generate .cer file

It is  a file representing certificate and is often published by server, to which you are trying to connect over SSL, so look for it. However if you do not posses this file, you can easily generate it.  You just need to start web browser and enter address of the  web service.  Confirm when browser asks for confirmation (“Accept security exception” or something like that). Now that we have accepted certificate in the web browser, we can easily export .cer file. I know that both Firefox and Opera have this export functionality, but probably other browsers have it as well. For Firefox it will be:

Tools -> Options -> Advanced -> Cryptography -> List certificates -> Export

2. generate keystore

Keystore can be generated using tool called “keytool”, that is included with every JDK. In command line type:

keytool -import -trustcacerts -keystore cacerts -storepass somepassword -noprompt -file cert.cer

where:

-file points to .cer file you generated a moment ago (here “cert.cer”)

-keystore is name of the generated keystore file, any name will suffice (here “cacerts”)

-storepass is password for the keystore (here “somepassword”)

3. setting properties

Last thing you need to do is to put generated keystore into your application and also set to global properties somewhere in your code:


System.setProperty("javax.net.ssl.trustStore",
                   "cacerts");
System.setProperty("javax.net.ssl.trustStorePassword",
                   "somepassword");

From now on, you should be able to connect to the server over SSL without any problems. Good luck :) .

See also:

  1. Other headache pills
h1

Wicket testing pitfalls and API issues

August 3, 2009

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
h1

Getting Started with Apache Wicket Refcards

July 31, 2009

MysticCoders released recently Refcard: “Getting Started with Apache Wicket”. Even though it sums up knowledge about 1.3.x version of the Wicket framework, I strongly recommend it as a starting point for Wicket learning curve.

And even if experienced with Wicket, take a look at the refcards, you might find thing or two, you didn’t know about.

h1

Wicket 1.4 is finally out!

July 30, 2009

After 7  release candidates, we finally get Wicket 1.4 ready for production code! More about the release here, code can be downloaded from the ususal site.

h1

Wicket HTML validator

July 30, 2009

Author of  “Wicket in Action” created this very cool Wicket HTML Validator.  Quoting its author:

“Even though you specify that your document is (X)HTML compliant, browsers will (fortunately) still work with these validation errors present.  While usually not destructive, having invalid markup can result in long debugging errors when replacing part of your page with for example Ajax, or traversing the DOM. The validator will notify you if you have invalid HTML markup in your rendered pages.

So if you have for example input tag not closed (<input wicket:id=”something”> not <input wicket:id=”something” />) validator will raise an error.

As I strongly support idea of catching as many bugs as possible during development and not production, I find this tool very useful. For more informations visit author’s blog or tools website.