NBuilder Utility for Child Complex Types

Posted on Updated on

NBuilder is a tool for .NET that allows the easy creation of test objects. It provides new instances of any class you provide (as a generic parameter) and those instances are populated with garbage data. I find that using NBuilder for test objects is a nice explicit way to show that the test does not care about the data but just needs an object in a decent enough state not to produce NullReferenceExceptions.

So given:


public class ComplexType
{
    public string Name { get; set; }
    public int Number {get;set;}
}

You could have the following test:


[Test]
public void Should_Return_Instantiated_Object_With_Test_Values()
{
    var result = Builder<ComplexObject>.CreateNew().Build();
    result.Should().NotBeNull();
    result.Name.Should().Be("Name1");
    result.Number = 1;
}

By the way that was also using FluentAssertions.

However, even after a fair bit of Googling I’m not sure why it does not include the creation of child complex objects, recursively. Instead these end up as null. So given:


public class OuterComplexType
{
    public int Number { get; set; }
    public InnerComplexType InnerComplexType { get; set; }
}

public class InnerComplexType
{
    public string Name { get; set; }
}

The following test would fail:


[Test]
public void Should_Return_Instantiated_Object_When_Given_Object_With_Complex_Properties()
{
    var result = Builder<OuterComplexType>.CreateNew().Build();
    result.InnerComplexType.Should().NotBeNull();
    result.InnerComplexType.Name.Should().Be("Name1");
    result.Number = 1;
}

So I wrote a little utility class that helped with this situation (see the Gist here). I have not used it in anger very much yet, so let me know if you spot any potential improvements.

using System;
using System.Linq;

using FizzWare.NBuilder;

namespace MarkGibaud.UnitTest.Utilities
{
    public static class NBuilderUtility
    {
        public static T Create<T>()
        {
            return (T)Create(typeof(T));
        }

        private static object Create(Type type)
        {
            if (type.IsInterface)
            {
                var firstConcreteImplementation = type.Assembly.GetTypes().FirstOrDefault(t => type.IsAssignableFrom(t) && !t.IsInterface);
                if (firstConcreteImplementation != null)
                    type = firstConcreteImplementation;
                else
                    return null;
            }

            var baseType = Build(type) ?? Build(Nullable.GetUnderlyingType(type));

            var complexTypeProperties = baseType.GetType().GetProperties().Where(p => !p.PropertyType.Namespace.Contains("System")).ToList();

            if (!complexTypeProperties.Any())
            return baseType;

            foreach (var complexTypeProperty in complexTypeProperties)
                complexTypeProperty.SetValue(baseType, Create(complexTypeProperty.PropertyType), null);

            return baseType;
        }

        private static object Build(Type type)
        {
            var builderClassType = typeof(Builder<>);
            Type[] args = { type };
            var genericBuilderType = builderClassType.MakeGenericType(args);
            var builder = Activator.CreateInstance(genericBuilderType);
            var createNewMethodInfo = builder.GetType().GetMethod("CreateNew");
            var objectBuilder = createNewMethodInfo.Invoke(builder, null);
            var buildMethodInfo = objectBuilder.GetType().GetMethod("Build");
            return buildMethodInfo.Invoke(objectBuilder, null);
        }
    }
}

Usage is something like this:

[Test]
public void Should_Return_Instantiated_Object_When_Given_Object_With_ComplexType_Properties()
{
    var result = NBuilderUtility.Create<OuterComplexType>();
    result.InnerComplexType.Should().NotBeNull();
    result.InnerComplexType.Name.Should().Be("Name1");
    result.Number = 1;
}

I guess the next step is to integrate this functionality into a fork of the NBuilder project…I’ll save that for a rainy day.

Advertisements

One thought on “NBuilder Utility for Child Complex Types

    Guffel said:
    December 27, 2012 at 3:04 pm

    That’s exactly what I was looking for! )

    Thanks!

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s