Home > XP > Get faster with FitNesse

Get faster with FitNesse

December 1st, 2008

This is the third article in a series beginning with Busting the great TDD myth and Keep your code ignorant and lazy. If you haven’t already read these articles I recommend checking them out as I will continue to use the same code as an example.

In the last article we looked at using the Provider pattern to make a flexible data access layer. It allowed us to test our TUserRepository in isolation even though it is dependent on data. Lets breifly review that code:

type
  ILoadable = interface
    procedure AddRecord(const UserName, Password : string);
  end;
 
  ILoader = interface
    procedure Load(Target : ILoadable); 
  end;
 
  TUserRepository = class(TInterfacedObject, ILoadable)
  private
    FUsers : TStringList;
  protected
    procedure AddRecord(const UserName, Password : string);
  public
    constructor Create(Loader : ILoader);
    destructor Destroy; override;
    function Lookup(const UserName : string) : TUser;
  end;
 
  TTestData = class(TInterfacedObject, ILoader)
  protected
    procedure Load(Target : ILoadable);
  end;

By having TUserRepository implement ILoadable and creating a stub for loading test data called TTestData we were able to write a test like this:

procedure TUserRepositoryTests.SetUp;
begin
  TestData := TTestData.Create;
  FRepo := TUserRepository.Create(TestData);
end;
 
procedure TUserRepositoryTests.TestValidLookup;
var
  user : TUser;
begin
  user := FRepo.Lookup('fred');
  CheckEquals('flinstone', user.password);
end;

What’s good about this arrangement is that we’ve tested the business logic of TUserRepository independent of a data source. However we’re left the question of how to write and test the actual production code that will provide live data to TUserRepository. We could test-drive this code in a unit test but the rules of TDD tell us that a test should not need external dependencies. Also, accessing a database in a unit test would slow down the test suite. So how do we test this code?

FitNesse

FitNesse is a framework for automated acceptance testing. It has two faces: the outward (or customer facing) wiki and the internal (or developer facing) framework. We’ll tackle the task of creating and test-driving the live data provider for TUserRepository using FitNesse.

Before taking on this task, the first thing you’ll need is a copy of FitNesse. You can download the latest version at the website fitnesse.org.

The first step will be to write the test. This takes shape as a page on your FitNesse wiki:

|UserRepoDataFixture|
|UserName|Password|
|fred|flinstone|

This will be rendered on the wiki page like this:

User repo data fixture table

User repo data fixture table

NOTE: I won’t cover how to create wiki pages in FitNesse. For this article I created a suite called SuiteExample and added a test page called TestUserRepoDataSource.

Clicking the Test link on the left side of the page will result in an error telling you that UserRepoDataFixture could not be found. So, you guessed it, the next step is to write the UserRepoDataFixture.

You need to grab the Delphi implementation of the FitNesse framework from the website http://code.google.com/p/fit4delphi/.

The test above is based on the Row Fixture. This sort of fixture is good for testing data sets. We’ll inherit our UserRepoDataFixture from TRowFixture.

type
  UserRepoDataFixture = class(TRowFixture)
  public
    function query : TList; override;
    function getTargetClass : TClass; override;
  end;

The Row Fixture requires that you do two things: (1) provide a list of objects that will represent the data set and (2) provide the class type of that object.

function UserRepoDataFixture.query : TList;
var
  user : TUser;
begin
  user.UserName := 'fred';
  user.Password := 'flinstone';
  Result := TList.Create;
  Result.Add(user);
end;
 
function UserRepoDataFixture.getTargetClass : TClass;
begin
  Result := TUser;
end;

You’ll see that we finally needed to add the UserName field to TUser. I know that some of you have been secretly screaming that TUser should have had this field from the start. Feel better? :)

We can build the fixture code and run the test and see that it passes. This is good because it tells us that our fixture code is being found and executed by the Delphi fit server. We still need to do the actual work:

function UserRepoDataFixture.query : TList;
var
  user : TUser;
begin
  Result := TList.Create;
  UserDS := TUserRepoDataSource.Create;
  Repo := TUserRepository.Create(UserDS);
  for user in Repo do
    Result.Add(user);
end;

What’s cool about this is that we didn’t have to instantiate our TUserRepository any differently than we did in our unit test. All we needed was to hand it a different implementation of ILoader.

Now some code for the TUserRepoDataSource:

type
  TUserRepoDataSource = class(TInterfacedObject, ILoader)
  private
    function Connect : Boolean;
    function MoreData : Boolean;
    function Current : TUser;
    procedure MoveNext;
  protected
    procedure Load(Target : ILoadable);
  end;
 
implementation
 
procedure TUserRepoDataSource.Load(Target : ILoadable);
begin
  if Connect then begin
    while MoreData do begin
      Taget.AddRecord(Current.UserName, Current.Password);
      MoveNext;
    end;
  end;
end;
 
{ SNIP }

I’ve omitted the rest of the implementation for the sake of brevity. You can tell from the Load method that this class would connect to a data source (such as a database) and loop over the result set to add each record to the ILoadable. I’ve also implied that we should add an enumerator to TUserRepository. This is one solution to the problem of how to pull the data out for the user repository. You might choose another based on your needs or your particular version of Delphi. The crux of the code is the same: load data into TUserRepository and read it back out.

Now we face the same problem as in the first article: our test relies on data. We can run this test and it might pass on our development box but fail on the build machine because our expected data is not present. One of the ways we can solve this problem is using the SetUp and TearDown facilities of FitNesse. We’ll add these pages to our SuiteExampe wiki page:

^SetUp
^TearDown

In the SetUp page we’ll add:

!|ExecSqlFixture|
|INSERT INTO User (UserName, Password) VALUES(’fred’, ‘flinstone’)|

In the TearDown page we’ll add:

!|ExecSqlFixture|
|DELETE FROM User WHERE UserName = ‘fred’|

Once that’s done out test page will render like this:

Test page with SetUp and TearDown

Test page with SetUp and TearDown

NOTE: At the time of this writing there are no database FitNesse fixtures written for Delphi. In this example I’ve used a fictional fixture called ExecSqlFixture. While it does not currently exist, writting this fixture shouldn’t be too much trouble.

Now our test assures our test data will be present before the test fixture is run and cleans up after itself at the end. This example presumes to use a SQL database as its data store. You might choose a different implementation and write different setup and tear down code.

Running the test now should find everything in order. Take some time and fiddle around with the test. Row Fixture does some neat things when you specify data that is not present and when you don’t specify data that is present.

Why is this better than what we did in the first article?

TDD prescribes that the tests should execute very fast. If they’re slow to execute then you won’t run then as often. So we move tests that are dependent on external dependencies out into the acceptance testing realm. We like this because it forces us to use a method that makes our code data source agnostic which in turn means we can test business logic in isolation. Using patterns like Factory or Builder we can take another step and write a number of different data access components and switch them in or out as we see fit.

FitNesse has considerably more benefits than what I’ve shown here. Because FitNesse is a wiki it’s easily accessible by non-tech types such as product owners and customers. In a perfect world the product owner and customer would have a suite of acceptance tests written before you started coding. These would act as executable product specifications … no more lengthy specs that get out of date and irrelevant!

I hope you enjoyed this three part series.

XP ,

  1. Andreas
    December 3rd, 2008 at 00:01 | #1

    Hi,
    thank you very much for this excellent series and for introducing FitNesse - I hadn’t heard of this! It solves the big issue I have with my unit tests - where to store the data so that it is visible and can be easily edited? I will dig deeper into this - thanks!
    Andreas

  2. December 3rd, 2008 at 08:52 | #2

    Glad to hear it Andreas. Good luck! Also, check out the other FitNesse related material here.

  3. February 12th, 2010 at 21:56 | #3

    Its so nice to see this good information in your post, I was looking the same which you post on blog, thanks now I have the thing which I was looking for, regards.

  4. April 6th, 2010 at 00:40 | #4

    it’s really a very good and elaborate instruction!

  5. May 14th, 2010 at 03:16 | #5

    Good! Really nice post!

  6. May 27th, 2010 at 03:34 | #6

    There are many collections available for receiving an education these days,you can buy term paper or buy research paper which is good news for those who have not yet managed. Truthfully, essays writing is not an easy product so try make right compromise between making on yor own or to buy custom essay papers. Maybe you need help with unique audit , maybe you want help in producing a fresh intention on a circumstance that is vast and complex.

  7. June 1st, 2010 at 05:31 | #7

    Thank you for this great series.
    Very interesting and entertaining.
    Well written!

  8. June 18th, 2010 at 16:56 | #8

    It’s a precise and informative article. Things are formed symptom less. Get to know lot’s of artifact which were unbeknownst to me. It’s truly one of the most facilitative article I get ever read. Thanks for to percentage sensing for author from you. Symmetrical I bookmarked this diplomat as asymptomatic for to get supply from it in incoming.

  9. essays
    July 2nd, 2010 at 13:20 | #9

    essay writing service will help you in learning and save your time

  10. July 2nd, 2010 at 13:21 | #10

    Thank ou so much for sharing this codes. This is a good resource.

  11. July 15th, 2010 at 00:25 | #11

    Thank you very much. I am wonderring if i can share your article in the bookmarks of society,Then more friends can talk about this problem.

  12. dfdsh
    July 24th, 2010 at 09:22 | #12

    Good article, thanks to the author to share.welcome come to
    http://www.footballworldcupjerseys.com.

  13. July 27th, 2010 at 18:52 | #13

    it was a wonderful chance to visit this kind of site and I am happy to know. thank you so much for giving us a chance to have this opportunity!

  14. July 28th, 2010 at 01:20 | #14

    An amazing machine, you deserve to 1. These fantastic shoes can be a brilliant and attractive. Enjoy and of itself.

  15. July 29th, 2010 at 04:00 | #15

    Many thanks for useful information!

  16. August 3rd, 2010 at 01:30 | #16

    I don’t usually reply to posts but I will in this case.

  17. August 3rd, 2010 at 18:10 | #17

    boring. i have seen these styles before. not original at all.

  18. August 18th, 2010 at 01:58 | #18

    We sincerely got a kick out of your post. It appears like you have really put a good amount of effort into your post and this world need a lot more of these on the net these days. I don’t have much to say in retort, I only wanted to comment to reply well done.

  19. August 18th, 2010 at 18:08 | #19

    Nice article, thanks for sharing this information.
    Good to know that this topic is being covered also in this web site.

  20. August 21st, 2010 at 03:23 | #20

    Truly impressive post about “Get faster with FitNesse”.

  21. August 21st, 2010 at 05:17 | #21

    I found your website perfect for my needs. It contains wonderful and helpful posts. I have read most of them and got a lot from them.

  22. August 22nd, 2010 at 03:02 | #22

    There were a lot of talks just about the custom term papers service. However, students would understand lots just about the essays writing service ordering example essays there.

  23. August 23rd, 2010 at 05:38 | #23

    Thanks for the live-tweeting of the hearings! I appreciated being able to keep up with the hearings, and your context.

  24. August 26th, 2010 at 19:06 | #24

    It is also the only facility on the Eastern Seaboard that can handle the massive new Moncler BRANSON Down Jacket Grey_for Men of LNG tankers. Irving is just as optimistic and sees itself as a potential market for Canaport gas. There’s room on-site to build a gas-fired generating plant, which Goodwin says could export electricity to the U.S. and provide a base-load for wind farms and turbines harnessing the Bay of Fundy’s mighty tides., Irving has provincial approval to test undersea turbines at 11 sites along the New Brunswick coast. The last piece of the puzzle is getting electricity to market. In March, Premier Graham and Maine Moncler black nylon down ‘Everest’ zip jacket John Baldacci joined forces to promote an “energy corridor” of transmission towers and pipelines through the state, to spur development and better connect New Brunswick energy producers to their customers. The province is desperate to see the project go through, but the proposal set offa political firestorm in Maine, where industrial customers, energy companies and unions banded together to force Moncler STRIPED TECHNICAL MENUIRE SPORT JACKET to ensure the state gets the best deal possible. In May, the state struck a committee to investigate Maine’s energy needs and to review proposals. A report, recommending ways to maximize economic benefits for the state, is due in early December. All this is forcing the company to act in a very unIrving-like way-discussing its plans and inviting public consultation and collaboration. Presenting a plan “developed within the walls of our company” is not an option, says Goodwin, who outlined Irving’s proposals to the committee in Moncler Nantes Hooded Down Coat. “The only project that will be right for the regionand ultimately, by extension, right for our company-will be one where everybody who has a stake in it has weighed in and has had a chance to shape it.”

  25. August 26th, 2010 at 22:54 | #25

    For this matter, once I discussed with one of my friends, not only about the content you talked about, but also to how to improve and develop, but no results. So I am deeply moved by what you said today.

  26. August 26th, 2010 at 22:55 | #26

    I tried to think so, but i found it was not as the same in the actual process. As you mentioned, I still have doubts, but really thank you for sharing!

  27. August 31st, 2010 at 23:37 | #27

    Things are formed symptom less. Get to know lot’s of artifact which were unbeknownst to me. It’s truly one of the most facilitative article I get ever read. Thanks for to percentage sensing for author from you. Symmetrical I bookmarked this diplomat as asymptomatic for to get supply from it in incoming.

  28. September 6th, 2010 at 19:26 | #28

    Also, accessing a database in a unit test would slow down the test suite. So how do we test this code?

  29. September 6th, 2010 at 23:25 | #29

    Nice article, thanks for sharing this information.

  1. March 2nd, 2010 at 13:01 | #1
  2. May 13th, 2010 at 08:15 | #2

*
To prove you're a person (not a spam script), type the security word shown in the picture. Click on the picture to hear an audio file of the word.
Click to hear an audio file of the anti-spam word