FitNesse Refactorings

I like to share some FitNesse refactorings which I think are quite useful. These refactorings will help you prepare your tests for those eternally changing requirements. This is the scenario:

I need to assert that if the user changes a property in a file that eventually it is changed in the database as well. What you could do is create methods for each property like property[PropertyName]IsChangedInto. With the check keyword in FitNesse you can assert whether or not the new value matches the expected value (There are more table rows before and after this one but I omitted those for readability):

TestPage


|check|property phone|is changed into|020 6666666|

This will of course result in many methods in your Fixture if you have many properties to check.

IntroduceParameter

You can solve this by making the phone property a parameter so then the fixture code will look like this:


|check property|phone|is changed into|020 6666666|

Now all we need is a mapping that maps phone to some field in our code that needs to be checked. The downside here is that if you are not careful your mappings wind up in different places in different Fixtures and if you refactor your Java code you also need to refactor the mappings. But like a great dutchman always says "Elk voordeel heb zijn nadeel" (there is a downside to everything).
Now I choose to put the mappings in the FitNesse page (you could also define 1 mapping class that contain all the mappings).

TestPage

|map|phone|to|contactDetails.phoneNumber|
|check|property|phone|is changed into|020 6666666|

I think the advantage of putting it into the FitNesse page over the Fixture code is that is more readable and clear what is mapped to what. Although the customer would not really care about this it is surely more readable for the programmer, and I think tests are for both customer and programmer. If the mapping becomes to big you could create a seperate page for it and include it in the TestPage see ExtractPage how to do this.

Now if we have that mapping in place the implementation of the propertyChangedInto method is fairly easy, escpecially if you use something like PropertyUtils from common-beanutils.

public String propertyChangedInto(String propertyName) {
  return PropertyUtils.getNestedProperty(instanceFromDatabase, mapping.get(propertyName)).toString();
}

ExtractPage and ExtractVariable

If you want to check more properties you could of course copy-paste the fitnesse table and change the phone to another field and change the contactDetails.phoneNumber accordingly. But that will result in too much repetition.
The solution I came up with is to extract a FitNesse page for the table and extract to variables. After refactoring the extracted FitNesse page, let's call it PageForTest, looks like this:

PageForTest

|map|${fieldName}|to|${mappedFieldName}|
|check |property|${fieldName}|is changed into|${newValue}|

And the resulting TestPage would then look like:

TestPage

!define fieldName {phone}
!define mappedFieldName {contactDetails.phoneNumber}
!define newValue {+31 020 666666}

!include TableForTest

And if you also need to test for instance the faxnumber:

TestPage


----Test for phone-----
!define fieldName {phone}
!define mappedFieldName {contactDetails.phoneNumber}
!define newValue {+31 020 666666}

!include TableForTest

----Test for fax-----

!define fieldName {fax}
!define mappedFieldName {contactDetails.faxNumber}
!define newValue {+31 020 777777}

!include TableForTest

By using refactorings like IntroduceParameter, ExtractPage and ExtractVariable you can create robust FitNesse tests. This way your tests are better prepared for coming changes in the requirements (and they will come).

Lars

Comments (2)

  1. Vikas Hazrati - Reply

    August 27, 2007 at 10:27 am

    Sounds great. But aren't we trying to put a logic into the fitnesse test page itself. Would the acceptance testers be able to use this scenario?

    It makes sense for developers who are used to logic but I am not sure if the customer who would be maintaining the fitnesse tables would be fine.

  2. Lars Vonk - Reply

    August 27, 2007 at 10:42 am

    Hi Vikas,

    Good point. Ideally the fitnesse pages should be created and maintained by the customers. I haven\'t seen that in practice though. I think developers always need to assist them, for instance for the fixture name, where to put the table borders etc. I think it is more important that customers are able to read the tests.
    But, if you have customers that are responsible for maintaining and creating the FitNesse test, you probably need to assess which refactorings are appropriate in your specific situation and which are not. Like the good old saying: \"It depends...\"

Add a Comment