Sat, 26 Mar 2005
Design-Driven Test-Driven Design (Part 2)
For background,
see
the first installment and the table of contents in the right
sidebar.
When working on a Fit test in the "flow" style (step-by-step
tests), it's my custom to start by creating empty methods for each
of the steps in the test. I do that because I usually find
something I don't like about the test, and I'd rather discover that
early.
Here's the resulting Fit output:
com.testingthought.humble.fixtures.dofixtures.InteractionDesign |
At
the beginning of the day, the caregiver navigates to the the SOAP
context and fills in today's SOAP.
the
starting context
is | inpatient |
choose patient | Betsy |
with owner |
Rankin | now |
the patient detail context
names | Betsy expected should return a patient actual |
navigate to
the | SOAP | context |
|
As I was writing the Java code for this most rudimentary DoFixture, I
noticed that the methods fell into groups. In what follows, I've
separated those groups with rules.
package com.testingthought.humble.fixtures.dofixtures;
import fit.DoFixture;
import fit.Parse;
public class InteractionDesign extends DoFixture {
// --------------
public void theStartingContextIs(String contextName) {
}
public void navigateToTheContext(String contextName) {
}
public String theContextBecomes(String ContextName) {
return "some visibility";
}
// --------------
public void choosePatientWithOwner(String animalName, String ownerName) {
}
// --------------
public String thePatientDetailContextNames() {
return "should return a patient";
}
public String thePatientDetailContextShows() {
return "should return a record";
}
public void chooseToEnterANewRecord() {
}
public String bothTheContextAndTheContextAre(
String firstContext, String secondContext) {
return "some visibility";
}
// --------------
public void recordThatTheAnimalIs(
String threeCharacteristics) {
}
public void recordThatItsTemperatureIs(String value) {
}
public void indicateThatTheSOAPIsFinished() {
}
// aliases for check - this is a clever hack due
// to Rick Mugridge.
public void now(Parse cells) throws Exception {
check(cells);
}
public void noteThat(Parse cells) throws Exception {
check(cells);
}
}
|
Except for the first one, the different groups talk about different interaction contexts. I could add
comments to explain that, like this:
// navigation
// inpatient context
// patient detail context
// soap entry context
|
But that would be wrong. To my mind, all the groups but one are crying
out to be extracted into classes. Those classes sure look like
they'll become the
Presenter objects that are going to implement our interaction
contexts. I'll extract them next time.
In the meantime, I've packaged up everything in a
zip
file. Feel free to fiddle. There's an ant build file in the
top-level directory. The default target compiles any changed files,
runs junit, then runs Fit. (I like to run junit before Fit, figuring
that there's no point in running Fit if any junit tests are
failing.) All the jar files you need should be in
the jars directory.
The test results for each HTML file in
the fit-tests directory are in a file with the same
name in the fit-test-results directory.
## Posted at 16:54 in category /fit
[permalink]
[top]
Guy Steele, Tester
Ever since I read the "lambda the ultimate" papers back in my Lisp
days, I've been awed by Guy Steele. So I read this with interest:
He also has an ability to focus very systematically on what he
describes as "nits and corner cases" -- an ability that came in handy
when he was asked to co-write the specification for the Java language.
"I pestered James [Gosling] with lots and lots of questions," he
recalls. "How does the language behave when you write this particular
statement, even though you'd never think of writing it in a real
program?"
His aim was to eliminate unintended consequences.
"I made a big matrix," he says. "The rows were the places you could use a type [a description of the set of values a variable can take on] and the columns were the kinds of types you could write. Then I checked each entry in the matrix to make sure the specification addressed what happened in that case.
I was pleased to read that because one of my habits is to take any
state diagram I get and turn it into a state table. The state table
contains a square for every event in every state. It forces you to
question what really happens in that case. (And you should be
careful not to leap to the conclusion that "it's impossible".)
State diagrams, in contrast, make it easier not to think about a case
- a missing arc is much less visible than an empty cell.
Such trudging-through-gruntwork is characteristic of testers,
but it needn't be isolated to them. It should be a property of the
team. I post the above quote to make it more glamourous.
Of interest to those who promote the idea that programmers should
practice, as
musicians do, is this:
Steele, a 10-year Sun veteran and winner of the 2005 Dr. Dobb's
Excellence in Programming Award, has written half a dozen
programming languages that exist simply as folders in his filing
cabinet.
"Designing technically competent programming languages is not that
difficult," he says.
To him they're like the finger exercises he used to do when he played
the piano -- a way to learn.
A final note: he has a huge shower, in which he spends about
twelve hours a day. I don't absolutely know that, but I deduce it
from the time I heard him say he only gets good ideas in the shower.
## Posted at 12:28 in category /testing
[permalink]
[top]
|