Monday, February 28, 2011

Replace code comments with unit tests

Not long ago code comments using XML was the thing. Every class and method should have some comment related to it. This worked great in the beginning until the code was updated and the comments were not. Eventually it all got out of sync and the comments were considered useless and were ignored.

The new trend today is to see unit tests as the documentation as they are (usually) up-to-date. By just reading the method names of the tests we should get the idea of what the code is actually doing. Consider the following method:

public void UpdateCustomerName(int customerId, string name, string email)
{
 if (string.IsNullOrEmpty(name))
  throw new ValidationException("Customer name cannot be empty.");

 _dataProvider.UpdateCustomerName(customerId, name);

 if (!string.IsNullOrEmpty(email))
  _mailSender.SendMail(email, "Your customer data has been updated.");
}

With the following unit tests:

[TestMethod]
[ExpectedException(typeof(ValidationException))]
public void UpdateCustomer_throw_exception_when_customer_name_is_empty()
{
 var dataProviderFake = MockRepository.GenerateStub<IDataProvider>();
 var mailSenderFake = MockRepository.GenerateStub<IMailSender>();

 var customerUpdater = new CustomerUpdater(dataProviderFake, mailSenderFake);

 customerUpdater.UpdateCustomerName(1, "", "");
}

[TestMethod]
public void UpdateCustomer_update_the_customer_name_in_the_database()
{
 var dataProviderFake = MockRepository.GenerateStub<IDataProvider>();
 var mailSenderFake = MockRepository.GenerateStub<IMailSender>();

 var customerUpdater = new CustomerUpdater(dataProviderFake, mailSenderFake);

 customerUpdater.UpdateCustomerName(1, "Bill", "bill@somecompany.com");

 dataProviderFake.AssertWasCalled(x => x.UpdateCustomerName(0, null), x => x.IgnoreArguments());
}

[TestMethod]
public void UpdateCustomer_email_customer_if_email_address_is_not_empty()
{
 var dataProviderFake = MockRepository.GenerateStub<IDataProvider>();
 var mailSenderFake = MockRepository.GenerateStub<IMailSender>();

 var customerUpdater = new CustomerUpdater(dataProviderFake, mailSenderFake);

 customerUpdater.UpdateCustomerName(1, "Bill", "bill@somecompany.com");

 mailSenderFake.AssertWasCalled(x => x.SendMail(null, null), x => x.IgnoreArguments());
}

By reading the method names we see the main logic of this method:
1. Throw exception when the customer name is empty.
2. Update the customer's name in the database.
3. E-mail customer if the e-mail address is not empty.

Conclusion: If we focus on writing unit tests with good method names then we can save ourselves from writing inline code comments.

Saturday, February 12, 2011

Is your iPad dead? Try this...


This morning my iPad suddenly went black. I tried to turn it on again by holding in the sleep button, but without success. I then remember having a similar problem with my iPod many years ago, and luckily the same fix that worked back then also worked for my iPad:

- Press and hold the sleep and home button until you see screen come on. This can take up to 20 seconds.