Posts tagged ‘Reflection’

I have just recently discovered the [TestCase] attribute of NUnit. With careful use it can drastically reduce the number of test methods you need to write. For my needs on a recent project I wanted to check field values which were being pulled from my database. What I’ve come up with is a simple extension to the NUnit Assert class which allows me to write test code such as …

[TestCase(0, "Forename", "Antony")]
[TestCase(0, "Surname", "Scott")]
[TestCase(0, "TwitterUserName", "antony_scott")]
public void ExampleTest(int index, string fieldname, object expectedValue)
{
    var result = GetPersonDetails();
    var list = result.ToList();
    Assert.IsFieldEqual(list.ElementAt(index), fieldname, expectedValue);
}

This gives me a very compact and easy to understand test with great visibility of any fields which are being pulled from the database correctly. All this is nothing new, as I’ve blogged about it previously here.

What I’ve added is the ability to dig into a structure like so …

[TestCase(0, "Forename", "Antony")]
[TestCase(0, "Surname", "Scott")]
[TestCase(0, "Twitter.UserName", "antony_scott")]
public void ExampleTest(int index, string fieldname, object expectedValue)
{
    var result = GetPersonDetails();
    var list = result.ToList();
    Assert.IsFieldEqual(list.ElementAt(index), fieldname, expectedValue);
}

In case you can’t see any difference, it’s the “dot” in the 3rd test case.

Here is the “extension” of the Assert class which makes it possible …

    public class Assert : NUnit.Framework.Assert
    {
        public static void IsFieldEqual(object obj, string propertyName, object expectedValue)
        {
            var type = obj.GetType();

            var dotIndex = propertyName.IndexOf('.');
            if (dotIndex != -1)
            {
                var innerObjName = propertyName.Substring(0, dotIndex);
                var innerPropName = propertyName.Substring(dotIndex + 1);
                var innerProp = type.GetProperty(innerObjName);
                var innerObj = innerProp.GetValue(obj, null);
                IsFieldEqual(innerObj, innerPropName, expectedValue);
            }
            else
            {
                var prop = type.GetProperty(propertyName);
                var actualValue = prop.GetValue(obj, null);
                AreEqual(expectedValue, actualValue);
            }
        }
    }

I recently wrote about using reflection to check for null values in conjunction with the TestCase attribute. I’ve just taken this a step further by creating a derived Assert class …

public class Assert : NUnit.Framework.Assert
{
    public static void IsFieldEqual(object obj, string propertyName, object expectedValue)
    {
        var type = obj.GetType();
        var prop = type.GetProperty(propertyName);
        var actualValue = prop.GetValue(obj, null);
        AreEqual(expectedValue, actualValue);
    }
}

This allows me to write tests to check the value of each field in a result object and have the assert fail on the specific field, it also doesn’t stop the other field being tested. So, using the TestCase attribute I can write tests such as this …

[TestCase("Forename", "Antony")]
[TestCase("Surname", "Scott")]
public void example_test(string fieldname, object expectedValue)
{
    // Arrange
    Context.AddPerson(new Person { ID = 1, Forename = "Antony", Surname = "Scott" });

    // Act
    var result = Service.GetPerson(1);

    // Assert
    Assert.IsFieldEqual(result, fieldname, expectedValue);
}

Obviously this is an over-simplified example. But, the idea is that I can now have a complex object being loaded up by an integration test into my database. I then use a Service of some kind (what I’m testing) to query my database and I can then make sure all the correct details have been retrieved from the database.

I recently had a need to write some unit (actually integration) tests which would check how I handled field being null. Without using the [TestCase] attribute of NUnit my tests would have looked something like this …

    public void validation_failure_identifier_null_400_expected()
    {
        // Arrange
        var resource = CreateCompleteResource();
        resource.Identifier = null;
        var jsonString = JsonPrettifier.Prettify(resource);

        // Act
        var result = Service.Post(jsonString);

        // Assert
        result.Message.CheckForValidationError("Identifier");
    }

    public void validation_failure_forename_null_400_expected()
    {
        // Arrange
        var resource = CreateCompleteResource();
        resource.Forename = null;
        var jsonString = JsonPrettifier.Prettify(resource);

        // Act
        var result = Service.Post(jsonString);

        // Assert
        result.Message.CheckForValidationError("Forename");
    }

… and so on.

BUT, by using a little reflection in conjunction with the [TestCase] attribute of NUnit, I can do this …

    private string GenerateJsonAndSetFieldTo(string fieldName, string value)
    {
        var resource = CreateCompleteResource();
        var type = resource.GetType();
        var prop = type.GetProperty(fieldName);
        prop.SetValue(resource, value, new object[0]);
        var jsonString = JsonPrettifier.Prettify(resource);
        return jsonString;
    }

    [TestCase("Identifier")]
    [TestCase("Forename")]
    public void validation_failure_400_expected(string fieldName)
    {
        // Arrange
        var jsonString = GenerateJsonAndSetFieldTo(fieldName, null);

        // Act
        var result = Service.Post(jsonString);

        // Assert
        result.Message.CheckForValidationError(fieldName);
    }

Obviously I have more TestCase’s than shown here, I didn’t want to bore you all with them! Less tests to maintain, easier to add null checking for other fields and it also looks neater in my test runner of choice.

I recently wrote about how to Automatically Add Framework Config Classes to the Model Builder. Since writing that post I have come across a situation where I was writing the exact same model class in a different application. That just didn’t smell right to me, since the other applications data access layer had been packaged up by nuget I could simply add a reference to it. That’s all well and good, but I didn’t want to have to go to any special effort to add the model configuration classes I needed to my modelbuilder. So, I’ve created a fairly simple (although it’s taken me a while to get it working how I want it) base class from which I can derive my context classes.

using System;
using System.Collections.Generic;
using System.ComponentModel.Composition.Hosting;
using System.Data.Entity;
using System.Data.Entity.ModelConfiguration;
using System.IO;
using System.Linq;
using System.Reflection;

namespace Base.EntityFramework
{
    public abstract class BaseDbContext : DbContext
    {
        protected BaseDbContext() { }
        protected BaseDbContext(string connectionString) : base(connectionString) { }

        private IEnumerable<Type> GetTypes()
        {
            var type = typeof(EntityTypeConfiguration<>);
            return GetType()
                .GetProperties(BindingFlags.Instance | BindingFlags.Public)
                .Where(p => p.PropertyType.IsGenericType &&
                            p.PropertyType.GetGenericTypeDefinition() == typeof(IDbSet<>))
                .Select(p => type.MakeGenericType(p.PropertyType.GetGenericArguments().First()))
                .ToArray();
        }

        private static void LoadAllEntityConfigurationsFromAllAssemblies(DbModelBuilder modelBuilder, IEnumerable<Type> types, string assemblyFilter, IEnumerable<string> namePartFilters)
        {
            var path = Path.GetDirectoryName((new Uri(Assembly.GetExecutingAssembly().CodeBase)).AbsolutePath);
            new DirectoryCatalog(path, assemblyFilter)
                .LoadedFiles
                .Where(x =>
                {
                    var fileNameWithoutExtension = Path.GetFileNameWithoutExtension(x.ToLower());
                    if (fileNameWithoutExtension != null)
                    {
                        var parts = fileNameWithoutExtension.Split(".".ToCharArray());
                        return parts.Any(part => namePartFilters.Any(namePartFilter => part == namePartFilter.ToLower()));
                    }
                    return false;
                })
                .Select(Assembly.LoadFrom)
                .ToList()
                .ForEach(assembly => assembly.GetTypes()
                                         .Where(t => types.Contains(t.BaseType))
                                         .Select(Activator.CreateInstance)
                                         .ToList<dynamic>()
                                         .ForEach(instance => modelBuilder.Configurations.Add(instance)));
        }

        protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {
            base.OnModelCreating(modelBuilder);

            var typesToLoad = GetTypes();
            LoadAllEntityConfigurationsFromAllAssemblies(modelBuilder, typesToLoad, "*.dll", new[] { "Data", "Domain" });
        }

    }
}

and in english ….

  1. Discover which classes for which I need to find and load the relevant EntityTypeConfiguration<> class. This is done with a little bit of reflection in the GetTypes() method.
  2. Use MEF to find the assemblies the config classes might be in. In this case it’s all of them (*.dll), but that could be changed to whatever is best for your situation.
  3. Use the namePartFilters to narrow down the list of assemblies further. In this case I’m looking for anything with “Data” or “Domain” in the filename (after it’s been split by periods).
  4. Load each assembly.
  5. Load any generic EntityTypeConfiguration types for the model classes used within my context class (the one which is derived from this base class).
  6. Instantiate each config class.
  7. Add it to the modelBuilder’s configurations.

Since this is a base class I can get this behaviour whenever I derive from it ….

    public class DomainContext : BaseDbContext, IDomainContext
    {
        public IDbSet<Employee> Employees { get; set; }

        public DomainContext() { }
        public DomainContext(string connectionString) : base(connectionString) { }

        IQueryable<Employee> IDomainContext.Employees { get { return Employees; } }
    }

What this allows me to do is use models from any assembly I am referencing in my application and just add it to my Context. Any configuration class for it will then be automatically added to the model builder.