Sunday, August 20, 2006

Unit tests are a newbie's best friend.

Contains all essential java nutrients?  Huh?Unit testing was a practice I picked up after years of programming, not because there is something difficult about it, but because I just didn't know. These days unit testing is the thing I do first in a language. It is the stick I use to poke at something new. For example, yesterday I was making my first foray into the Ruby/Rails world, specifically I was working with Active record. Here are the tests I wrote while playing with it.


require 'book'

class BookTest < Test::Unit::TestCase
def test_book_creation_works
war_and_peace = Book.new("title" => "War and Peace")
war_and_peace.save
mystery_book = Book.find_first "title = 'War and Peace'"
assert war_and_peace.title == mystery_book.title
end

def test_unit_tests_are_independent
mystery_book = Book.find_first "title = 'War and Peace'"
assert mystery_book == nil
end

def test_book_requires_a_title
bitter_ejb = Book.new
assert !bitter_ejb.save
end
end


It is too bad that a tool this useful and simple isn't something recommended to beginners early on. I am picturing programming 101 being test driven from now on. Perhaps it is time to retire "Hello, World!" in favor of an assertion. assertEquals("Hello, World!", atom.greeting()); A new programmer's first task will be a green bar, not a println.

What got me thinking about this was that I just came across the first computer science book I ever owned. It is a cute paperback from circa 1998 called Computing Concepts With Java Essentials by Cay Horstman. It comes bundled with a totally awesome cdrom containing Microsoft Visual J++ 1.1! If anyone needs a copy I'll be happy to burn it for you :)

I thought I'd take a tour down memory lane so I cracked the book. Table of Contents: Section 1 "What is a computer?", Section 2 "What is programming?" Wow, this class must have been hard. Initially I was disappointed that it didn't have anything sounding completely antiquated, although the picture of a "personal computer" in the section entitled "Anatomy of a Computer" makes me want to pop in WingCommander and flip the turbo switch. I guess the fact that my first CS book is still mostly relevant is Good news. I'm still a young'n! Oh look, a section on testing in chapter 7. Here is some sample code for a "unit test" from section 7.1 (note: this is the book's formatting, not mine)

import ccj.*;
public class SqrTest1
{ public static void main(String[] args)
{ boolean done = false;
while (!done)
{ double x = Console.in.readDouble();
if (Console.in.fail()) done = true;
else
{ double y = squareRoot(x);
System.out.println("square root of " + x
+ " = " + y);
}
}
}

public static double squareRoot(double a)
{ if (a < = 0) return 0;
double xnew = a/2;
double xold;
do
{ xold = xnew;
xnew = (xold + a/xold)/2;
}
while (Numeric.compareDoubles(xnew, xold) != 0);
return xnew;
}
}

I have to admit I got a big kick out of this book's idea of a unit test, but I suppose Junit was still pretty young. This article mentions a bit about the history of xUnit and I get the impression that Junit came about in 97. Back to the code, obviously there are some annoyances here. This unit test can't be automated because they require your input. There are no assertions, just a println. You have to check the output by hand! We are a looong way from green bars here folks. There are two other examples of unit tests in the book, and they do a bit better in that they automate the test input and ensure boundry cases are covered, but they still leave it up to the developer to get out a calculator and check the results. Another major annoyance is that the methods under test are actually in the test classes. I certainly hope the author didn't expect the students to have duplicates of every method they wanted to test! However in the book's defense the following section has good basic information about selecting test cases, test suites, regression tests, and test coverage.

Obviously the ideas were all there in 1998, but the implementation hadn't filtered down to the introductory college level. I hope that things have changed since then. I hope that the section on unit testing has moved from chapter 7 to chapter 1, and I hope it is a concept that is sprinkled throughout the book. If the code solutions I grade for our recruiting team are any indication, perhaps things haven't changed that much. In that case this is my advice to all beginning level programmers. Tell your instructor to skip the Hello World exercise and move straight on into unit testing.

2 comments:

Shlomo said...

Though the thought of foraying the world of Ruby/Rails leaves me as rapturous as an athiest with a prayerbook, I have to say that you are a clever writer; even for audiences who mostly don't get what you are saying. And, I think you're cute.

Shlomo said...

sorry.