August 27, 2014
Hot Topics:
RSS RSS feed Download our iPhone app

Considering Test-After Development

  • September 19, 2007
  • By Jeff Langr
  • Send Email »
  • More Articles »

Test-Driven Development

With the more ad hoc TAD approach, I wrote a wider test first, one that allowed introduction of a larger chunk of code all at once. I used my skills and experience to drive the introduction of those two minutes of for-loop coding. That approach seemed to have worked well enough, but I did have to remember to go back and bolster things with an additional test.

The approach using test-driven development (TDD) is to start with the simplest possible case instead of the most typical case. What's the simplest case I can think of? Well, what if the string is null? I write my first test, which takes me about 30 seconds. (I have to get the test class in place to support the first test, like the TAD solution, but it's a simpler test.)

@Test
public void answersNullForNullText() {
   assertEquals(null, new Reverser().reverse(null));
}

That's easy! Within 10 seconds, I have a passing implementation in place:

public String reverse(String text) {
   return null;
}

Already, I have a test that I didn't have before, plus I have a more robust implementation. A novice programmer can easily remember to start from null as the simplest case.

Going back to the TAD solution, my experience failed me. Upon adding a new after-the-fact test, I discover that the reverse method throws a NullPointerException if passed a null input string. I'm sure I'd have thought to code for that, given enough time (or perhaps someone might have reminded me at our next code review session).

The next simplest step is the empty string:

import static org.junit.Assert.*;
import org.junit.*;

public class ReverserTest {
   private Reverser reverser;

   @Before
   public void initialize() {
      reverser = new Reverser();
   }

   @Test
   public void answersNullForNullText() {
      assertEquals(null, reverser.reverse(null));
   }

   @Test
   public void answersEmptyStringForEmptyString() {
      assertEquals("", reverser.reverse(""));
   }
}

Writing the test, plus refactoring to a common setup, takes about 30 seconds. The implementation again takes a few seconds (about 10):

public String reverse(String text) {
   return text;
}

For the second time, I document a case that I probably wouldn't have worried about when doing TAD. Fortunately, this is a test that does pass against the existing TAD solution. But what's better about the TDD solution is that the document—the test named answersEmptyStringForEmptyString—provides a piece of instantaneous information. In its absence, I would have had to spend time gleaning that information from careful code analysis of the TAD solution.

In about 15 seconds, I write the case for a single-word string, and realize that the implementation need not change (in other words, the tests already pass).

@Test
public void answersInputForSingleWord() {
   assertEquals("one", reverser.reverse("one"));
}

The next case, an input string that contains two words (15 seconds):

@Test
public void swapsTwoWords() {
   assertEquals("two one", reverser.reverse("one two"));
}

This failing test triggers the following implementation (about 30 seconds):

public String reverse(String text) {
   if (text == null)
      return null;
   String[] words = text.split(" ");
   if (words.length == 1)
      return words[0];
   return words[1] + " " + words[0];
}

My initial solution doesn't include the guard against text being null. That omission breaks the test answersNullForNullText, something I rectified rapidly.

For the next test, I could jump to the multi-word input that requires a loop in the solution. But, my interest in finding a next increment of solution in rapid time triggers the thought, "What if the two words are separated by more than one space?" I take 15 seconds to code this test:

@Test
public void eliminatesExtraSpacesBetweenWords() {
   assertEquals("two one", reverser.reverse("one  two"));
}

The implementation, very specific to the needs of the test:

public String reverse(String text) {
   if (text == null)
      return null;
   String[] words = text.split("\\s+");
   if (words.length == 1)
      return words[0];
   return words[1] + " " + words[0];
}




Page 2 of 3



Comment and Contribute

 


(Maximum characters: 1200). You have characters left.

 

 


Sitemap | Contact Us

Rocket Fuel