Demystifying The Code

Using the Builder Pattern in tests

One of the most painful parts of writing tests is creating test data.  Whether you use mocking frameworks or write your own fakes, one thing is constant… you will find yourself creating object instances over and over.  You have to create inputs to the methods you are testing, return values for stubs or mocks, data in fake repositories, etc.  The Builder Pattern can greatly ease this burden.  In this post, through example, I will show how.

The Scenario

The following is  a simplified version of Coupon and Order types from DevEducate.com:

public class Coupon

{

    public int Id { get; private set; }

    public string CouponCode { get; set; }

    public decimal Discount { get; set; }

    public DateTime ExpirationDate { get; set; }

    public string Description { get; set; }

    public int ExecuteMaxTimes { get; set; }

    public decimal MinimumOrderAmt { get; set; }

    public CouponType CouponType { get; set; }

 

    …

}

public enum CouponType
{
    PercentOffOrder = 1,
    AmountOffOrder = 2
}
public interface IOrder
{
    decimal SubTotal { get; }
}
 
public class Order : IOrder
{
    public decimal SubTotal
    {
        get
        {
         …
        }
    }
    …
}

In this simplified scenario, we have a Coupon that can represent a percent off an order (25% off orders of $200 or more) or a fixed amount off an order ($25 off orders $100 or  more).  Notice that we can use the MinimumOrderAmt property to ensure the order is of a certain value.  We can also use ExecuteMaxTimes to limit the number of people that can cash in on the coupon and we can set an ExpirationDate to limit the lengh of time the coupon is executable.

Now, suppose we want to start implementing the CalculateDiscount method for our Coupon type.  One test may look something like this:

[Test]
public void CalculateDiscount_TenPercentOffOrderOfTwoHundred_ReturnsTwenty()
{
    //Arrange
    var coupon = new Coupon()
                     {
                         CouponCode = "TestCode",
                         CouponType = CouponType.PercentOffOrder,
                         Discount = .10m,
                         ExecuteMaxTimes = 100,
                         ExpirationDate = DateTime.Today.AddYears(1),
                         MinimumOrderAmt = 0
                     };
 
 
    var order = MockRepository.GenerateStub<IOrder>();
    order.Stub(x => x.SubTotal).Return(200m);
 
    //Act 
    var result = coupon.CalculcateDiscount(order);
 
    //Assert
    Assert.AreEqual(20, result);
}

 

The object under test here is obviously the Coupon, specifically the CalculateDiscount method.  The first thing I do here is to create an instance of our Coupon.  That is quite a bit of code just to create an instance of our Coupon.  You might argue that I have set some properties here that are unnecessary for the test (CouponCode, for example) just to make the example look worse.  However, it is likely that I would have to set most of those properties. 

What if instead of all of that code I could have done the following:

    //Arrange
    var coupon = new CouponBuilder()
        .WithCouponType(CouponType.PercentOffOrder)
        .WithDiscount(.10m)
        .Build();

Ore even:

    //Arrange
    var coupon = new CouponBuilder().AsValid().WithPercentageDiscount(.10m).Build();

 

The Builder Pattern

The Builder Pattern is a construction pattern.  It’s purpose is to abstract away the construction of (complex) objects and enable you to easily construct / build an object in a step-by-step process.  And, if done just so, like above, it can yield a nice, fluent interface (notice how I simply chain methods together).  So let’s get started implementing our CouponBuilder:

A Simple Builder

public class CouponBuilder
{
    private readonly Coupon _coupon;
    public CouponBuilder()
    {
        _coupon = new Coupon();
    }
 
    public Coupon Build()
    {
        return _coupon;
    }
 
    public CouponBuilder WithCouponCode(string couponCode)
    {
        _coupon.CouponCode = couponCode;
        return this;
    }
 
    public CouponBuilder WithDiscount(decimal discount)
    {
        _coupon.Discount = discount;
        return this;
    }
 
    public CouponBuilder WithExpirationDate(DateTime expirationDate)
    {
        _coupon.ExpirationDate = expirationDate;
        return this;
    }
 
    public CouponBuilder WithDescription(string description)
    {
        _coupon.Description = description;
        return this;
    }
 
    public CouponBuilder WithExecuteMaxTimes(int executeMaxTimes)
    {
        _coupon.ExecuteMaxTimes = executeMaxTimes;
        return this;
    }
 
    public CouponBuilder WithMinOrderAmount(decimal minOrderAmount)
    {
        _coupon.MinimumOrderAmt = minOrderAmount;
        return this;
    }
 
    public CouponBuilder WithCouponType(CouponType couponType)
    {
        _coupon.CouponType = couponType;
        return this;
    }
 }

 

In it’s simplest form, it is that simple.  Here is the breakdown:

  • You start by creating a readonly field representing the type you want to construct
  • You initialize that field in the constructor of your builder
  • You create a series of methods that act on the instance stored in that field.  Each method returns an instance of the Builder.  This allows for that fluent interface.

More complex builder methods

I mentioned that this is the simplest form – a one-to-one relationship between builder method and property I want to set.  You need not do that.  You can add builder methods that logically bundle up the setting of multiple properties.  Some simple examples for our example would be adding an AsValid() and WithDiscount(decimal discount).  Let’s see that:

    public CouponBuilder AsValid()
    {
        return WithExecuteMaxTimes(100)
            .WithExpirationDate(DateTime.Today.AddYears(1))
            .WithMinOrderAmount(0);
    }
 
    public CouponBuilder WithPercentageDiscount(decimal discount)
    {
        return WithCouponType(CouponType.PercentOffOrder)
            .WithDiscount(discount);
    }

 

Smart Defaults

In most of my builders, I set some smart defaults in the constructor.  That is, I set the defaults to be those most commonly used in my tests.  Here is the updated CouponBuilder ctor:

public CouponBuilder()
{
    _coupon = new Coupon();
    WithCouponCode("TestCode")
        .WithCouponType(CouponType.PercentOffOrder)
        .WithDiscount(.25m)
        .WithDescription("Test Description")
        .WithExecuteMaxTimes(100)
        .WithExpirationDate(DateTime.Today.AddYears(1))
        .WithId(1)
        .WithMinOrderAmount(0);
}

 

Private Setters

Notice how my Coupon class has a private setter.  It is a common and good practice to make ids immutable.  However, you may want to have the ability to set your id for testing purposes.  Our builder class is a perfect place for that.  (*** remember that this will just be used in our tests).  Have a look at my WithId builder method:

public CouponBuilder WithId(int id)
{
    _coupon.GetType().GetProperty("Id").SetValue(_coupon, id, null);
    return this;
}

 

Conclusion

The Builder Pattern is a great tool for, among other things, constructing objects for your tests.  Writing them up front will save you loads of time throughout the lifetime of your project.  Personally, I have a simple ReSharper template I use to create the Builder methods.  Feel free to email me and I will send it to you…

Speak Your Mind

Tell us what you're thinking...
and oh, if you want a pic to show with your comment, go get a gravatar!

Demystifying The Code