July 23, 2014
Hot Topics:
RSS RSS feed Download our iPhone app

Writing a Simple Automated Test in FitNesse

  • December 15, 2006
  • By Jeff Langr
  • Send Email »
  • More Articles »

You want to verify application functionality by using FitNesse. The application might be a web application, a web services API, a desktop UI, or something else. For the example, you'll simplify things and verify against a simple Java API.

Dive in! First, the application. You've built some code to track late fees on checked-out books in a library system. The core class, Checkout, appears in Listing 1.

Listing 1. Checkout.java.

package com.langrsoft.app;

import java.util.*;

public class Checkout {
   private Date checkoutDate;
   private Material material;
   private Date returnDate;

   public Checkout(Material material, Date checkoutDate) {
      this.material = material;
      this.checkoutDate = checkoutDate;
   }

   public Material getMaterial() {
      return material;
   }

   public Date getCheckoutDate() {
      return checkoutDate;
   }

   public boolean isReturned() {
      return returnDate != null;
   }

   public Date getReturnDate() {
      return returnDate;
   }

   public void returnOn(Date date) {
      returnDate = date;
   }

   public int daysLate() {
      return DateUtil.daysAfter(getDueDate(), returnDate);
   }

   public Date getDueDate() {
      return DateUtil.addDays(checkoutDate,
         material.getCheckoutConstraints().getPeriodAsDays());
   }

   public boolean isInGracePeriod() {
      return daysLate() <=
         material.getCheckoutConstraints().getGracePeriod();
   }

   public int amountToFine() {
      if (isInGracePeriod())
         return 0;
      return daysLate() *
         material.getCheckoutConstraints().getCentsPerDay();
   }
}

Some of the supporting classes and interfaces appear in Listing 2. The function of methods in the DateUtil class, not shown, should be fairly obvious. All code, including JUnit tests, is available for download—check the link at the end of this article.

Listing 2. Supporting classes.

package com.langrsoft.app;

public interface Material {
   CheckoutConstraints getCheckoutConstraints();
}

// --------------------------------------

package com.langrsoft.app;

public interface CheckoutConstraints {
   int getPeriodAsDays();
   int getGracePeriod();
   int getCentsPerDay();
}

// --------------------------------------

package com.langrsoft.app;

public class Book implements Material {
   protected static final int BOOK_CHECKOUT_PERIOD = 21;
   protected static final int BOOK_GRACE_PERIOD    =  3;
   protected static final int BOOK_FINE            = 10;

   public CheckoutConstraints getCheckoutConstraints() {
      return new CheckoutConstraints() {

         public int getCentsPerDay() {
            return BOOK_FINE;
         }

         public int getGracePeriod() {
            return BOOK_GRACE_PERIOD;
         }

         public int getPeriodAsDays() {
            return BOOK_CHECKOUT_PERIOD;
         }};
   }
}

The code shows that you construct a Checkout object with a material (book, movie, and so forth) and a checkout date. The customer paying for your library system wants to ensure that you're correctly calculating fines for materials returned late.

Late fine calculation is reasonably easy. Materials have a checkout period that represents the number of days a patron can borrow a material before it's late. The system obtains the due date by adding the checkout period to the checkout date. If the number of days late is less than or equal to the grace period, there is no fine. Otherwise, the fine is the number of days late times the daily fine amount.

You want to script some tests so that you can prove your system works—both for yourself and for your customer. To satisfy your customer, you'll need these scripts to express things clearly. You'll use FitNesse to accomplish these goals.

To store the test, you create a new FitNesse page, TestCheckout. By naming the page starting with the word "Test," FitNesse knows to recognize your new page as a test page. Upon saving TestCheckout, an additional button marked Test appears in the left-hand margin. If you forget to name a page appropriately, you can always click the Properties button in the left-hand margin and click on the Test checkbox.

You edit the contents of TestCheckout so that it contains the following:

!path c:Fitnessefitnesse.jar
!path C:Documents and SettingsjlangrMy Documentsworkspace
         gamelanLibrarybin
!path C:Documents and SettingsjlangrMy Documentsworkspace
         gamelanLibraryFixturesbin

!|fixtures.BookRules|
|daily fine?|grace period?|checkout period?|
|10|3|20|

The first three !path lines add to the FitNesse classpath. FitNesse needs to know where to look for test fixtures, which are bits of Java code you will create that interface with the Checkout application. It also needs to know the location of the FitNesse library itself, as well as the location of the application. In an integration environment, these usually would be references to JAR files. (You will need to change the path statements to reflect appropriate locations on your machine.)

The second set of lines represents a test table, also known as a FIT (Framework for Integrated Tests) table. The pipe or bar symbol, |, separates columns in the table. The ! prior to the table escapes the table, so that FitNesse does not interpret any of its contents as wiki words.

The first line of the table is the fixture name, fixtures.BookRules. A fixture is an intermediary between the FIT table and the application you're testing. You will be developing your fixtures in Java, although it's possible to develop fixtures in other languages, such as C#. The fixture name corresponds to the fixture class name, so you must code the fixture in the fixtures.BookRules class.

The second line of the table represents column headers. You have three headers: daily fine?, grace period?, and checkout period?. Column header names ending with a ? are queries, so all of your columns represent queries. The goal of a query column is to extract some information from the application (via the fixture code), and verify that it matches data in the column.

The third line of the table represents an actual row of data. For each row in a table, FitNesse will make calls out to the fixture code. Here, FitNesse will ask the fixture for each of daily fine, grace period, and checkout period, and compare it against the expected values of 10, 3, and 20, respectively.

The fixture code appears in Listing 3.

Listing 3. fixtures.BookRules.

package fixtures;

import com.langrsoft.app.*;

import fit.*;

public class BookRules extends ColumnFixture {
   public int dailyFine() {
      return new Book().getCheckoutConstraints().getCentsPerDay();
   }

   public int gracePeriod() {
      return new Book().getCheckoutConstraints().getGracePeriod();
   }

   public int checkoutPeriod() {
      return new Book().getCheckoutConstraints().getPeriodAsDays();
   }
}

The class fixtures.BookRules extends from the class fit.ColumnFixture, which can be found in fitlibrary.jar. You'll need this JAR on your classpath to compile fixtures.BookRules.





Page 1 of 2



Comment and Contribute

 


(Maximum characters: 1200). You have characters left.

 

 


Sitemap | Contact Us

Rocket Fuel