Chapter 8: The InputCommand Object


We thought the code was telling us that it wanted another object, so we gave it another object. Was the code then happier ? Were we? Read and find out...

Recap

In Chapter 7, Warts and All, we set up an acceptance test that allowed the customer to say where the cursor was in the input and to condition the output based on that result. Then we went down a rat hole and backed out the code. We had identified that we needed an object, and we sketched the way that object would be used. The object we wanted was called InputCommand, and the idea was that it would be able to answer the clean input (the input except with the cursor position indication removed) and the selection start (the location of the input cursor). The code we wanted to make work looked like this:

 private void SetInput(StringReader reader) { 
InputCommand input = new InputCommand(reader);
model.Lines = input.CleanLines();
model.SelectionStart = input.SelectionStart();
}

At this point, there was no InputCommand class, so this was all just speculation. We set out to create this class. Therefore, we needed a test. Here s the first test we wrote:

 [Test] public void EmptyCommand() { 
command = new InputCommand();
Assert(1==1);
}

Once we made that work, by creating an empty class named InputCommand, we extended the test to say

 [Test] public void EmptyCommand() { 
command = new InputCommand();
AssertEquals(0, command.CleanLines().Length);
}

The idea is that there s no input, so CleanLines will return an array of String of length zero. We built a CleanLines method that returned new String[0], which made that work. So far, so good.

We like writing these trivial tests. It s tempting to really do something, but, as we learned in Warts and All, we get into trouble when we try to do too much. Starting every class this same way gives us a nice rhythm, and we rarely get into trouble. We ve found it s better to keep things simple. Try it ”it might work well for you also.

But sooner or later we have to do some work, and now s the time. Looking at the place where we actually intend to use this code, we see that the InputCommand wants to be driven from a StringReader. So we wrote a new test requiring a StringReader:

 [Test] public void OneLineCommand() { 
String oneLineString =
@"one line
*end";
StringReader reader = new StringReader(oneLineString);
command = new InputCommand(reader);
AssertEquals(1, command.CleanLines().Length);
}

This seems pretty simple. We re getting better at knowing how to work C#, although there s probably a better way to do this. We create a string that matches some legal input, create a StringReader on it, create an InputCommand on that, and assert that we get one line back from CleanLines(). That test doesn t even compile, because InputCommand doesn t have a constructor on StringReader. We debated whether to write a second constructor, to learn about overloads, but decided that would be a digression. So we changed our first test to use a StringReader also, like this:

 [Test] public void EmptyCommand() { 
command = new InputCommand(new StringReader(""));
AssertEquals(0, command.CleanLines().Length);
}

Fine. We have two tests that won t compile, because there s no such constructor, and we build the constructor:

 private ArrayList lines; 
public InputCommand(StringReader reader) {
lines = new ArrayList();
String line = reader.ReadLine();
while (line != null && line != "*end") {
lines.Add(line.TrimEnd());
line = reader.ReadLine();
}
}

(One of my editors noticed that we have InputCommand tied unnecessarily to StringReader, and he suggested that Reader would have been a better choice. It would have been; in our inexperience, we just didn t think of it.)

We decided to use an ArrayList for the member variable lines, which was what we were using internally in the original CustomerTest. We just read to "*end" and add the lines to ArrayList. And we implemented CleanLines to return the ArrayList. There was a little discussion on that: the rest of the code isn t clear on whether it wants arrays of strings or ArrayLists, and we decided that we like ArrayList better and we d deal with any changes that we needed. The first change we needed was to change the .Length calls in our tests to .Count because the number of items in an ArrayList is .Count, while the number of items in an array is .Length. Now our two tests look like this:

 [Test] public void EmptyCommand() { 
command = new InputCommand(new StringReader(""));
AssertEquals(0, command.CleanLines().Count);
}
[Test] public void OneLineCommand() {
String oneLineString =
@"one line
*end";
StringReader reader = new StringReader(oneLineString);
command = new InputCommand(reader);
AssertEquals(1, command.CleanLines().Count);
}

And now the InputCommand CleanLines method looks like this:

 public ArrayList CleanLines() { 
return lines;
}

The earlier version was answering an empty array of String. At this point, all our tests run. We did a little Ann Anderson goal line victory dance [1] and then got back to work. The thing is, the lines aren t really clean. CleanLines() is supposed to strip out any vertical bars (the cursor location indicator) that are in the input. We haven t written a test that calls for that, so we write it:

 [Test] public void OneDirtyLine() { 
command = new InputCommand(new StringReader("ab\n*end"));
AssertEquals("ab", command.CleanLines()[0]);
}
}

That should be enough to do it. We put in ab and expect ab back.

Lesson  

Let s emphasize again how simple and tiny our tests have been. Certainly we could have put the vertical bar into the second test. If we had, however, we would not have been able to just answer lines back as the result. Now, returning lines is simply wrong, as we ll see in a minute, but in fact we had lots of work to do, with the constructor and adjusting .Length to .Count and so on.

We didn t foresee that there would be enough to do without the added complexity of the vertical bar; we just try always to take tiny little steps. It usually makes the job easier, by requiring us to worry about less and keep less in mind. This was just one of those times.

[1] It s valuable to celebrate our small victories. Ann likes to jump up and do a little dance. Some teams have a little bell that they ring. Others are satisfied with a high five.




Extreme Programming Adventures in C#
Javaв„ў EE 5 Tutorial, The (3rd Edition)
ISBN: 735619492
EAN: 2147483647
Year: 2006
Pages: 291

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net