Exploration Through ExampleExample-driven development, Agile testing, context-driven testing, Agile programming, Ruby, and other things of interest to Brian Marick
|
Wed, 30 Mar 2005Design-Driven Test-Driven Design (Part 3) For background, see the table of contents in the right sidebar. The story so far: the way methods have clustered in a Fit DoFixture has persuaded me that I need to make some new classes. Heaven help me, the image that comes to mind is viral particles budding off a cell. (The image on the right shows flu viruses.) I also know that I want to move toward the Model View Presenter pattern, because it should let me get most of the UI code safely under test. And I'm driving my work using scripts / tests of the sort a User Experience (UX) designer might write.
The first time I worked through this script, I created a single
class per method-cluster. For the methods that referred to the
"patient detail interaction context", I created a
PatientDetailContext class. The fixture would send it commands
like The problem was that no test ever drove me to split that one class into the View and Presenter classes. If you think about it, that makes sense. In order to preserve design flexibility and keep detail from obscuring the essence, the test script I'm working from is deliberately vague about the details of the user interface. Since Model-View-Presenter calls for the View to do little more than relay low-level GUI messages over to the Presenter, the programmatic interface between the two (which I think of as like the mitotic spindle in cell division - what's with me today?) has to name a bunch of detail that the script leaves out. Where can that detail come from? I think it has to come from my knowledge of my end goal. So in this do-over, I'll start by assuming such low-level messages. But rather than jump into two classes right away, I'll start by budding out the Presenter and have the DoFixture act as the View (the self-shunt pattern). Let's take two steps in the script to work from:
Here would be the object structure and pattern of communication for the first line:
A portion of the DoFixture acts as a kind of mock View for the Inpatient
Presenter, pretending to respond to user actions. Its implementation
of
Those look rather like UI messages. The Inpatient Presenter knows
that when "Choose Patient" is clicked, it should tell the Patient
Detail Presenter about it. The Patient Detail Presenter in turn has
to update its View. Its View is, again, the DoFixture. So the Presenter calls a
new method on the DoFixture,
Now when the next test line claims that "now the patient detail context names Betsy", Fit calls a query method that returns the right result:
That works (given the right code in the presenters). Having gotten green, I can now refactor. There are two uglinesses in this code.
By an amazing stroke of luck, I can now extract the View-ish methods into full-fledged mock View objects that implement my new interface. They will:
Like this:
I won't show the code itself, but you can find it in a
zip
file. As before, the We've now achieved the View/Presenter separation. The mock Views do conversions. The "from" part of the conversion comes from the Fit tests, but where does the "to" part of the conversion come from? What tests directly drive the the decision about what messages to send from Views to Presenters? Well, what always drives the coding of classes distant from the "top" of the system? - unit tests. That's kind of an interesting inversion. Usually, we think of the code that handles UI widgets as being on the outside of the system, the part closest to the user. But here that code is utility code, not really different from database access code. By burying utility code behind a layer (be it a persistence layer or a DoFixture derived from an interaction design), we let people thinking about larger issues ignore the grotty technology that lies behind the business value of the system. Next: interlacing Views and mock Views. Plus, I finally get around to learning to program Cocoa. |
|