3/13/2009

Tests and Blank Lines

Add blank lines please.

This might sound stupid and, indeed, alternate DSL's for unit testing are making this less of an issue but there are still a lot of the old XUnit frameworks that prevent isolation of the 3 areas of your tests.

Every test you have needs to be setup, executed and validated. Let's start with a Java example.

public static void testSomething()
{
Address address = new Address();
address.setName("The House");
address.setLine1("1234 Street Ave");
address.setCity("Cityville");
address.setCountry("US");
address = dao.geocode(address);
assert_equals(-86.234, address.getLatitude());
assert_equals(46.234, address.getLongitude());
}


What does this test do? Which lines of code are being tested? Ok, lets try again with blank lines.

public static void testSomething()
{
Address address = new Address();
address.setName("The House");
address.setLine1("1234 Street Ave");
address.setCity("Cityville");
address.setCountry("US");

address = dao.geocode(address);

assert_equals(-86.234, address.getLatitude());
assert_equals(46.234, address.getLongitude());
}


Doesn't that help? A simple change and you can clearly see the three areas of your code.

I hear you shout "setup method", I know but junit sucks in that the only way to write enough tests with enough setup's is to have lots of separate test classes. Certainly go that way if you have a complex class to test but simpler stuff can be done in one class with a little setup and tests with blank lines.

OK, what is the future of these blank lines? Well, Ruby has unit test libraries like Shoulda that make these concepts easy to express.

context "an address" do

setup do
@address = Address.new(
:name => "The House",
:line1 => "1234 Street Ave",
:city => "Cityville",
:country => "US"
)
end

should "be geocoded to a specific lat and long" do

@address = @address.geocode

assert -86.234, @address.latitude
assert 46.234, @address.longitude
end
end


This allows us to separate and describe the areas of our tests, however, common usage has taken this API to the next level which, I think speaks to the need for the original idea behind the blank lines.

context "an address" do

setup do
@address = Address.new(
:name => "The House",
:line1 => "1234 Street Ave",
:city => "Cityville",
:country => "US"
)
end

context "when geocoded" do

setup do
@address = @address.geocode
end

should "have a specific latitude" do
assert -86.234, @address.latitude
end

should "have a specific longitude" do
assert 46.234, @address.longitude
end
end
end


As you can see, the use of the sub-context for each "test" and the use of the setup method to actually run the test, allows us to isolate the specifics of what the test is all about and describe each area.

1 comment:

Steve Gentile said...

I like blank lines

It's like creating a new paragraph when reading a book