Brainstorming a test list

Question — When writing code test first, how do you know where to start, how do you know what to do next, and how do you know you’re finished?

Answer — By creating a list of tests that help you bound the problem you’re solving.

Given that previous statement, it sounds like having a good set of tests is a pretty important part of Test Driven Development, eh? Obviously it is, so the question becomes how you create a good list.

Creating a good test list is a skill that needs to be learned and practiced. It’s an important thing to do because it is our first act of design as we start to build something. It also helps us create our roadmap through the creation of the method, from start to finish, so that we always have a good idea of where to go next.

When I approach creating a test list, I specifically ignore the concept of tests and think about examples I want to teach my code to do. I start by thinking of simple examples that exercise the basic, but extremely limited, functionality of my method, and then start to layer on more complexity with subsequent examples. When I’ve thought of as many examples as I need to flesh out the total behavior, I start thinking about examples of what I’d like to happen when things start to go wrong. Once I’ve finished those, I have a pretty good idea of all the things I need to teach my code to do, and I’m ready to start implementing. Let’s look at a simple problem as a way of further explaining what I mean:

Let’s consider a method that reverses the elements in an array of integers and returns them in a new array. The first example I might think of is:

  • An array of a single integer is returned unchanged, in a new array

This example forces me to write enough code to define what my input parameter is, what my return parameter looks like, and establishes that I’m returning my information in a new array. So far, so good. This simple example has started to flesh out the publicly visible portions of this class.

My next example would expand on this, adding in the ability to reverse a larger array:

  • An array with multiple elements is returned in reverse order in a new array

Since this problem is so simple, those two examples might be enough to flesh out the basic behavior of this method. That leaves me with considering corner cases and exceptional conditions. To define that behavior, I think these last two example should suffice:

  • A null array causes an ArgumentNullException to be thrown
  • An empty array is returned as a new empty array

I think those 4 examples should be enough to define the behavior of this problem well enough that I could code it.

Are we really finished?

I said back up top that I would say a few more words about “being done” later in this entry, and that time has come. The thing about writing a test list is that it very much like any sort of designing on paper — it is a guess. You don’t truly know if you’re done until the code is written and working in its final environment. The only real feedback about whether or not you defined the right set of examples is whether or not your code works correctly. If you find that you have to add additional functionality to finish your method, then you missed a test. If you later find bugs in the code, you’ve missed a test. When either of these two cases happens, however, fret not. Think of it not as a failure, but as an opportunity to learn 🙂 I’m never concerned that I think of all the tests/examples at first, because I know I can always modify my test list as I go. What I am concerned about, however, are bugs that I let slip through from missing tests. In that case, I should reflect on what test I could have written to find that bug while the code was being written and write that test and others like it next time.

That’s all there is to it — no muss, no fuss, no guilt. If you mess up and miss a test, learn from it, and do better next time.

Conclusion

The act of writing a test list is an act of design. It is the first concrete opportunity for the developer to really think about what this particular method is about to do. Having a test list allows you to focus on incrementally developing your method, from a simple example to those that are more complex, until you’re finished.

In our next episode…

If you’d like to play along with our game, you can think about creating a test list for a query string builder for a web request. I know there is already one in .Net, but forget about that one for now. Try to figure out a list of tests that you could create that would guide you from the simplest case to the final product, including any and all corner cases you can think of. The problem statement would be:

Given a URL and an array of name/value pairs, create a syntactically correct query string, suitable for use on the web.

I’ll share my version with you early next week, from sunny, warm West Palm Beach, Florida 🙂

— bab

find -name foo.* | xargs grep “find_me”

[Update from Brad Wilson and Scott Dukes]

I’ve been wanting a powershell script to replace my favorite unix command for ages, and I took a stab at it today. This got me very close to what I wanted yesterday, which was just the names of files where the matches occurred.

get-childitem -include foo.* -recurse | where-object { get-content $_ | select-string find_me }

Scott Dukes pointed out that select-string would take the FileInfo object that was passed to it and search through the contents for the string file_me, and this would give me the exact same kind of output my unix command used to. Thanks, Scott! This command was exactly what I needed.

Brad went way past this and showed some very interesting other changes to the script to do some cool things.

Thanks again to both of them for correcting this PowerShell newbie. I’ve been a long-time Unix scripting weenie, with bash code flowing out my fingertips at will (in XEmacs of course :)), but I think PowerShell just blows that away.

— bab

Powershell script to convert RTF docs to plain text using MS-Word

On our current project, we had a bunch of RTF files that had some text in them that we wanted to yank out and store in a database. Instead of laboriously opening and resaving each of the files as plaintext, I decided to write what I had hoped would be a simple PowerShell script to do that for me. What follows is my best try at that script.

I am very open to any questions, criticisms, and improvements in the script, as I’m still very much learning the language. And my fundamental question is really, was PS the right tool to use for this job?

Enjoy!

— bab

=============== Reformat.ps1 ================

function translate_from_rtf_to_text([System.Io.FileInfo] $source_file)
{
    $source_file_name = $source_file.FullName
    $dest_file_name = create_destination_file_name($source_file)

    write-host "Copying from $source_file to $dest_file_name"

    $rtf = $word.Documents.Open($source_file_name)
    $rtf.SaveAs([ref]$dest_file_name, [ref]$saveFormat)
}

function create_destination_file_name([System.Io.FileInfo] $source_file)
{
    $dest_file_name = $source_file.Name.Remove($source_file.Name.Length - $source_file.Extension.Length) + ".txt"
    $dest_directory = $source_file.DirectoryName
    $dest_file = join-path $dest_directory $dest_file_name

    return $dest_file
}

if ($args.Length -ne 1)
{
   write-host "Usage: Reformat.ps1 <path to root directory of rtf files>"
   exit 1
}

$path = $args[0]

write-host Converting all rtf files under directory $path...

$word = new-object -com Word.Application

$saveFormat = [Enum]::Parse([Microsoft.Office.Interop.Word.WdSaveFormat], "wdFormatTextLineBreaks")

get-childitem -path $path -include *.rtf -recurse | foreach-object -process { translate_from_rtf_to_text $_ }

$word.Quit([ref]$true)

Announcing the 2nd Annual St. Louis Code Camp

At long last, I can officially announce the 2007 St. Louis Code  Camp, to be held May 5th, in Creve Coeur, MO. The code camp will be held in the offices of Microsoft at Three City Place, at the corner of Ballas and Olive, and will meet from 8:30 until 5. Final plans for the number of sessions we can accept are still being drawn up, but we should have enough room for lots of good presentations.

A web site is in the process of being updated at www.stlcodecamp.org. On that site will soon be the camp schedule, list of speakers, map to the camp location, and a link to register. Registration is going to be limited to about 150 people due to size constraints of our facility.

Call for Volunteers

Much help is still being sought in organizing. If you’re interested in volunteering, please email me at codecamp-volunteers@agilestl.com.

Call for Speakers

This will also serve as the first Call for Speakers. If you want to speak at the code camp, please register on the site and add the your session. This is a non-competitive speaker selection process, so the first speakers who register will be given speaking slots until the slots fill up. Feel free to speak on any development-related topic, including Java, C++, C#, .Net, Ruby, Lua, Agile programming techniques, Unix, Linux, MacOS, Windows, AOP, or anything else you’re passionate about. The only requirement is that your presentation and any sample code must be made available to all code camp attendees with no restrictions on their use. Sessions can be added through the website shortly. 

This blog will serve as the primary means of announcing news about the St. Louis Code Camp until  the web site is set up. Once that is updated, all news and information will be available from there.

For more information on Code Camps

You can get more information on what code camps are and how you can contribute at http://blogs.msdn.com/trobbins/archive/2004/12/12/280181.aspx . If you have any other questions, please drop me a note, and I can help answer your question.

Thanks, and I look forward to seeing many of you there!

— bab