Shooting for an Acceptance Test
Hooking Up to Fitnesse
Faithful readers know that we always begin with a trivial test, often named HookUp. Chet spent a long time Wednesday and we spent our whole session Thursday, just trying to get our Fitnesse HookUp to run. The issue was that it kept reporting that it wasn’t finding things, and no combination of paths seemed to work. Finally we backtracked through everything, experimented around, and got it going. The top test page looks like this:
!path fitnesse.jar !path C:/Data/workspaces/patternProject/PatternProject/ this is the front page for acceptance tests for the pattern project. This page contains the class path. ^SanityTest ^FileReadTest
And displays like this …
SanityTest, the initial hookup test, looks like this:
!|com.hendricksonxp.patterning.fitnesse.HookUp| |in|out()| |hi|hi|
And the HookUp class looks like this:
package com.hendricksonxp.patterning.fitnesse; import fit.ColumnFixture; public class HookUp extends ColumnFixture { public String in; public String out(){ return in; } }
What we learned was simple, and probably you knew it already: The fixture name in the ! line of the test lists the fixture’s fully qualified package and class name. The path (classpath) line lists the pathname down to the workspace and project folder. No other combination seemed to work. The result looks like this:
Two hours of trial and error to sort that out. Fun.
First Acceptance Test
But today, Friday, we were ready to go. Now we’ll do our first real Fitnesse test, building a fixture that will actually run against our real shotgun objects.
We’re going to test something very simple, to get things going. The idea is to read a simple bitmap file and prove to the customer that we have done so by displaying the center of gravity from that BMP. The test, FileReadTest, looks like this:
this test will read a bmp file and discover the pixels. This table reads the file named in the fileName field, creates a ShotPattern object, and stores it in a public static field on the CreatePatternFromFile class. The ShotPattern can then be accessed by subsequent test tables. !|com.hendricksonxp.patterning.fitnesse.CreatePatternFromFile| |fileName|doIt()| |x4y9on7x12.bmp| true| Using the ShotPattern created in the previous table, verify the pattern's center. !|com.hendricksonxp.patterning.fitnesse.CenterOfMass| | xCenter() | yCenter() | | 1 | -3 |
Notice that we have a setup “test”, CreatePatternFromFile, and an actual test, CenterOfMass. This is the standard way that we know to specify parameters in a Fitnesse test and then use them. The CreatePatternFromFile fixture will read the file, and put the resulting ShotPattern object in a “well-known” place:
package com.hendricksonxp.patterning.fitnesse;
import com.hendricksonxp.patterning.model.ShotPattern;
import fit.ColumnFixture;
public class CreatePatternFromFile extends ColumnFixture {
public String fileName;
final String folder = "..\\Data\\";
public static ShotPattern pattern;
public Boolean doIt(){
pattern = new ShotPattern(folder + fileName);
return true;
}
}
Then for the CenterOfMass test, we create a fixture that grabs that ShotPattern, and returns the xCenter and yCenter values. The first time we did it this way:
package com.hendricksonxp.patterning.fitnesse; import fit.ColumnFixture; public class CenterOfMass extends ColumnFixture { public int xCenter() { return CreatePatternFromFile.pattern.xCenter(); } public int yCenter() { return CreatePatternFromFile.pattern.yCenter(); } }
To support that, we turned the xCenter and yCenter methods of ShotPattern to public. The test runs!
We didn’t really want xCenter and yCenter to be public – we were just feeling the need to get the test to run quickly before our luck ran out. So then we declared them private again, and changed the fixture to do it right:
public class CenterOfMass extends ColumnFixture { public int xCenter() { return CreatePatternFromFile.pattern.centerOfMass().getX(); } public int yCenter() { return CreatePatternFromFile.pattern.centerOfMass().getY(); } }
The test still runs and we’re good to go: a real Fitnesse test, satisfying our customer (Chet) that we can really read the bmp file and find the center of mass. (He believes that because he created the file and hand-calculated the center of mass.)
Summing Up
To get this to work at home, after leaving Borders, I had to do a lot of work. My folder and workspace setup were different from Chet’s, so I had to sync those up. That took two or three tries to convince Eclipse and Subclipse that I was a good person, and I had to download the entire project anew from Chet’s subversion server in his basement.
What we have done at the moment is that we have all of Fitnesse, including all of its help pages, inside our workspace and project, so that first download was a big one. Presumably when I check in in a few minutes, it won’t be so bad. Let’s see: it went smoothly from here. We’ll see whether Chet can find it OK … no real changes, just some Fitnesse pages edited a bit I think.
So … in two sessions, plus some home work, we have Fitnesse running under our project, and we have an acceptance test running, albeit a simple one. It took less time to make it work than it did to write about it and snip all the pictures in the article.
We have some fun ideas for future tests, but we need to learn some tricks about Fitnesse that we don’t currently know … we’ll see if the fitnesse yahoo group folks can help us. Now let’s check the mail:
Cards and Letters
A number of good suggestions came from all over when I mentioned that we weren’t sure how to embed data files in the system. We wound up just using a relative path to reach them. Thanks to all who chipped in on the list and privately on that one. We’ll show the code the next time we’re down that way.
Jonas Bengtsson expressed surprise that I started by parsing the BMP file directly, rather than using a library. Jim Cakalic remarked, also regarding use of libraries:
Franky, after reading about your encounter with the Java Rectangle class and your conclusions as to the utility of using publicly available libraries, I'm surprised to hear that you're using Eclipse or any other publicly available software. Why not write your own IDE? Then you'd know exactly how it works.
I’m not sure why he called me Franky, but I do want to comment again on the use of libraries. There were at least two effects working:
- Chet searched for useful libraries and found writeups that were mostly confusing, and looked like they would take a lot of time. Recall that our direct read of the BMP, for example, only took a couple of hours and we were on our way. After friendly folks pointed us to better libraries, we replaced that code with some Raster reading code.
- I am, by nature, inclined to get pretty close to the metal for things like this. The abstractions that libraries generally present seem often to be overblown for our simple purposes. When searching in the file reading pages for what we used, the writeups were not crystal clear in my opinion, for example referring to "samples" as if one knew what those were. The file model is very general for reading these things, and it took quite a bit of time even to imagine that I understood just what it was getting at. When we have been lucky enough to find a decent example somewhere, we've tried it. But when we don't find one quickly, and we're on another mission, it doesn't trouble me to code something up that digs in the bits, because I know how to do it, and I'm not troubled by replacing it later if and when we find a better way.
Apparently Jim’s mileage varies, and yours may as well. That’s totally fine, and as it should be. What we do in these articles is to report what really happens, not going back to clean up the messes. If the only way to learn from us is by taking us as a bad example, so be it. We’re confident that we’ll be able to do a bit better than that.
In that light, we are perhaps two days in, and we have these things actually working, and all under JUnit test:
- We can read bitmap files, including a file that's a photo of a real shotgun blast.
- We can find the center of mass of an arbitrary bitmap, and are apparently finding the correct center of the actual blast photo.
- We can calculate shot density in arbitrary rectangles, and in fixed sectors that will readily be parameterized when we get the story to do that.
- We have a customer-understandable Fitnesse test running, showing the center of mass calculation on a small file that the customer can understand.
This is, again, the work of a couple of days of work time, three at the most. I’m not saying that to claim that we’re particularly great: if you had been with us I’m sure that things would have gone faster. I would claim, however, that we’re pretty good at picking very simple approaches to getting where we’re going. We hope that you’ll be able to pick up some tips from what happens as we go along.
But agreeing or not, please keep communicating with us: we like to know you’re out there. Thanks! Oh … I have a gig next week, so articles may be a bit sparse … we’re not sure yet. Stay tuned!