NBuilder is fantastic for generating object graphs

 

A library which I have not seen used often enough is NBuilder. On my current project we needed to create a WCF service for consumption by a 3rd party. Since the structure of the web service was agreed beforehand, we wanted to publish an early version for them to connect to.

Instead of manually hand cranking the test data that the API was to return, we were able to use NBuilder to do 90% of the work, with overrides to handle more complex cases.

You can also use it in your unit tests wrapped by a builder pattern to create common object graphs for use by your tests.

We created some common interfaces for our builders to get a default setup of an object, which we could then use the provided builder methods to override.

public interface IBuilder<T>
{
    ISingleObjectBuilder<T> GetDefault();
}

public interface IManyBuilder<T>
{
    IListBuilder<T> GetDefault();
}

Next we implemented default builders to get the common configured setup. NBuilder has generators for many common types, and iterates through the object graph populating dummy data.

public class CustomerBasketBuilder : IBuilder<Basket>
{
    public ISingleObjectBuilder<Basket> GetDefault()
    {
        var basketItems = new CustomerBasketItemsBuilder().GetDefault().Build();

        var basket = Builder<Basket>
            .CreateNew()
            .With(basket1 => basket1.BasketItems = basketItems)
            .With(basket1 => basket1.ItemCount = basketItems.Count)
            .With(basket1 => basket1.CustomerId = new PrimitiveBuilder().GetCustomerId())
            .With(basket1 => basket1.TotalBasketValue = basketItems.Sum(item => item.BasePrice));

        return basket;
    }
}

 

Whenever we use the With method here, we are setting up an override over the default generators. I manually call the BasketItemsBuilder to get the default setup for a list of items, and then ask NBuilder to Build the object graph using a combination of my overrides with the default generators.

public class CustomerBasketItemsBuilder : IManyBuilder<BasketItem>
{
    public IListBuilder<BasketItem> GetDefault()
    {
        var generator = new UniqueRandomGenerator();
        
        var basketItems = Builder<BasketItem>
            .CreateListOfSize(10)
                .All()
                    .With(item => item.ItemId = generator.Next(100000, 999999))
                    .With(item => item.Colour = Pick<string>.RandomItemFrom(new[] { "Red", "Green", "Blue" }))
                    .With(item => item.ItemType = BasketItemType.Product)
                    .With(item => item.ValidOperations = new[]
                                                             {
                                                                BasketItemOperations.CanSaveForLater,
                                                                BasketItemOperations.CanDelete,
                                                                BasketItemOperations.CanEdit
                                                             });
                
        return basketItems;
    }
}

 

UniqueRandomGenerator is one of the OOTB generators, which is normally called implicitly, however we needed a defined range in this case. The Pick methods are also useful for one liner random item choosing. I strongly recommend going through the NBuilder codebase to see what’s available. There’s some real gems in there which unfortunately are not documented.

Here’s a refactored sample from one of our tests:

Before After
image image

 

It turns out refactoring unit tests is really satisfying, and reduces stress, I highly recommend it.

June 25 2011

Comments (1) -

michaelciba

Really liking the use of the interfaces for the builders and the creation of a default base object which can then be amended as needed.

michaelciba | 7/1/2011 6:04:39 AM |

Comments are closed