NBuilder is fantastic for generating object graphs

by Naeem Khedarun 24. June 2011 15:31

 

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.

Categories: C# | Unit Testing

Configuring Log4net in code using Windsor Installers

by Naeem Khedarun 23. June 2011 14:41

 

Castle provides a great way to structure the setup of your application using the installers. Ninject providers a similar mechanism with modules which you could also use.

Managing configuration was getting pretty painful on my current project, so cutting it down was necessary. Since we don’t need to edit most of the log4net configuration after a build is done, compiling this in is acceptable.

We are using the log4net facility for castle, so this is the first thing we set up.

public class LoggingInstaller : IWindsorInstaller
{
    public void Install(IWindsorContainer container, IConfigurationStore store)
    {
        if (!container.Kernel.GetFacilities().OfType<LoggingFacility>().Any())
        {
            container.AddFacility("logging", new LoggingFacility(LoggerImplementation.Log4net));
        }

        var root = ((Hierarchy)LogManager.GetRepository()).Root;
        root.AddAppender(GetEventLogAppender());
        root.Repository.Configured = true;
    }
}

 

Next we set up an EventLog appender using the built in object model provided by log4net.

private static IAppender GetEventLogAppender()
{
    var patternLayout = new PatternLayout("%appdomain [%thread] %-5level - %message%newline [%properties]%newline %exception");

    var eventLogAppender = new EventLogAppender
                               {
                                   Name = "Application",
                                   Layout = patternLayout,
                                   ApplicationName = "MyApp",
                                   SecurityContext = NullSecurityContext.Instance
                               };
    return eventLogAppender;
}

 

And after calling container.Install(new LoggingInstaller()) we have logging without writing a single line of XML!

Categories: C# | Windsor | log4net

WCF, RouteTables and Castle Windsor

by Naeem Khedarun 7. February 2011 21:27

 

We are using the routing functionality to give our RESTful WCF service nice endpoints, however I ran into trouble, none of our services were being injected.

The service had two constructors which seemed odd, an empty one and one with dependencies specified…

public Api()
{
}

public Api(IBasket basketService)
{
    _basketService = basketService;
}

The injected services were NULL, so I removed the public constructor and got:

image

This sounds like the default WCF factory at work, checking the SVC files we get:

<%@ ServiceHost 
    Language="C#" 
    Factory="Castle.Facilities.WcfIntegration.DefaultServiceHostFactory, Castle.Facilities.WcfIntegration" 
    Service="MyProject.Api" 
%>   

That’s also configured correctly, but we have overridden the default routing, let’s take a look at that:

RouteTable.Routes.Add(new ServiceRoute("Api", new ServiceHostFactory(), typeof(Api)));

That looks like the default WCF factory to me… Doh! Let’s fix that up…

RouteTable.Routes.Add(new ServiceRoute("Api", new DefaultServiceHostFactory(container.Kernel), typeof(IApi)));

Great, we are now using the windsor factory, and we can remove the default parameter-less constructor from our API service.

Tags: , ,
Categories: WCF | C# | Windsor

NBehave alpha now shipping with Should assertion framework

by Naeem Khedarun 29. October 2010 01:47

 

It recently came to my attention (when dog-fooding the new version), that I wasn’t able to make any assertions!

Using NBehave without a unit testing framework means we need some other way of checking our results. So I’ve included the Should framework to complete the testing story.

I’m finding it quite a nice framework to use, and its very feature complete. I’ve ILMerged it into the main NBehave.Narrator.Framework assembly, so you don’t need to pull in any references!

Personally I prefer the Fluent API which is quite friendly to intelli-sense, and readability. Here’s an example for a test I’m writing now:

[Then("I should get the available sessions")]
public void ThenIShouldGetTheAvailableSessions()
{
    sessions.Count().Should().Be.GreaterThan(0);
}

You can grab the new version here.

Categories: NBehave.Plugin | NBehave | BDD | C#