Friday, December 31, 2010

AutoMock is out on CodePlex

The first version of AutoMock is now out on CodePlex. AutoMock is a small library that simplifies the process of doing unit testing with a mocking framework. Without AutoMock, the process of unit testing a class that uses dependency injection, involves creating mocks for each dependency and injecting these into the class under test. This is both repetitive and boring, especially on classes with many dependencies. AutoMock simplifies this process by creating the mocks for you, together with an instance of the class under test. This saves us some lines of code for every test we write, it also makes the test smaller in size, thus easier to read and understand. Check out http://automock.codeplex.com for more information. Below is some sample code.

The class to test:
The class below uses constructor based dependency injection. It updates the data source with the customer name, writes a new event to the log and sends a notification e-mail.


public class CustomerUpdater
{
 private ICustomerDataProvider _customerData;
 private IMailSender _mailSender;
 private ILogWriter _logWriter;

 public CustomerUpdater(
  ICustomerDataProvider customerData,
  IMailSender mailSender,
  ILogWriter logWriter)
 {
  _customerData = customerData;
  _mailSender = mailSender;
  _logWriter = logWriter;
 }

 public void UpdateCustomerName(int customerId, string name, string email)
 {
  var customer = _customerData.GetCustomer(1);

  customer.Name = name;

  _customerData.UpdateCustomer(customer);

  _logWriter.Write(string.Format("Customer {0} has been updated", name));

  _mailSender.SendMail(email, string.Format("Customer {0} has been updated", name));
 }
}

Unit test without using AutoMock:


[TestMethod]
public void UpdateCustomerName_email_should_be_sent()
{
 var customerData = MockRepository.GenerateStub<ICustomerDataProvider>();
 customerData.Expect(x => x.GetCustomer(0)).IgnoreArguments().Return(new CustomerItem());
 var mailSender = MockRepository.GenerateStub<IMailSender>();
 var logWriter = MockRepository.GenerateStub<ILogWriter>();

 var customerUpdater = new CustomerUpdater(customerData, mailSender, logWriter);

 customerUpdater.UpdateCustomerName(1, "Frank", "frank@somecompany.com");

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

Unit test using AutoMock:


[TestMethod]
public void UpdateCustomerName_email_should_be_sent()
{
 var autoMocker = new RhinoAutoMocker<CustomerUpdater>();
 autoMocker.Get<ICustomerDataProvider>().Expect(x => x.GetCustomer(0)).IgnoreArguments().Return(new CustomerItem());

 autoMocker.ClassUnderTest.UpdateCustomerName(1, "Frank", "frank@somecompany.com");

 autoMocker.Get<IMailSender>().AssertWasCalled(x => x.SendMail(null, null), x => x.IgnoreArguments());
}