Tales about Aviation, Coaching, Farming, Software Development

Why I love test-driven development

Here is a very good example why I am a big fan of TDD (test-driven development). Instead of writing a specification or a requirements document I wrote the following test case and let Eclipse create a few new classes for me. Then I wrote enough code to get the basic functionality right and added a mock UserService with a few expectation set.

public class EnrollmentTest extends TestCase {
  public void testSignupTrialWithoutPayingOrganization() throws UserNotFoundException {
    PaymentDetails paymentDetails = new CreditCardDetails() ;

    Person firstPerson = new Person() ;
    firstPerson.setRfc822Address("sns@caimito.net") ;

    Person secondPerson = new Person() ;
    secondPerson.setRfc822Address("fidel@caimito.net") ;

    UserService userService = EasyMock.createMock(UserService.class) ;
    EasyMock.expect(userService.findUser(firstPerson.getRfc822Address())).andThrow(new UserNotFoundException()) ;
    userService.saveUser(new User(firstPerson.getRfc822Address())) ;
    EasyMock.expect(userService.findUser(secondPerson.getRfc822Address())).andThrow(new UserNotFoundException()) ;
    userService.saveUser(new User(secondPerson.getRfc822Address())) ;
    EasyMock.replay(userService) ;
    SignupManager signupManager = new PerUserSignupManager() ;
    signupManager.setUserService(userService) ;

    try {
      Customer customer = signupManager.signup(firstPerson, paymentDetails) ;
      User firstUser = customer.createUserAccount(firstPerson) ;
      assertNotNull(firstUser) ;
      assertEquals(firstPerson.getRfc822Address(), firstUser.getUsername()) ;
      User secondUser = customer.createUserAccount(secondPerson) ;
      assertNotNull(secondUser) ;
      assertEquals(secondPerson.getRfc822Address(), secondPerson.getUsername()) ;
    } catch (SignupFailedException e) {
      fail(e.getMessage()) ;
    } catch (UserAlreadyExistsException e) {
      fail(e.getMessage()) ;

This test case is very high-level. There is more to be implemented. The work of implementing the details can be distributed amongst the members of a team. That way everybody gets involved a bit, which is good to foster shared ownership of the code base, and it allows to delegate some easier tasks to Junior Developers.

Such a high-level test case can be used as well by a Senior Developer with more design experience to more precisely prepare a task for a learner. The high-level design is there and the Junior Developer can fill in the missing pieces and design a bit of the lower level parts. He will be able to learn good design and contribute working code to the project.