Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

StructureMap: How can i unit test the registry class?

I have a registry class like this:

public class StructureMapRegistry : Registry
{
    public StructureMapRegistry()
    {
        For<IDateTimeProvider>().Singleton().Use<DateTimeProviderReturningDateTimeNow>();
    }

I want to test that the configuration is according to my intent, so i start writing a test:

public class WhenConfiguringIOCContainer : Scenario
{
    private TfsTimeMachine.Domain.StructureMapRegistry registry;
    private Container container;

    protected override void Given()
    {
        registry = new TfsTimeMachine.Domain.StructureMapRegistry();
        container = new Container();
    }

    protected override void When()
    {
        container.Configure(i => i.AddRegistry(registry));
    }

    [Then]
    public void DateTimeProviderIsRegisteredAsSingleton()
    {
        // I want to say "verify that the container contains the expected type and that the expected type
        // is registered as a singleton
    }
}

How can verify that the registry is accoring to my expectations? Note: I introduced the container because I didn't see any sort of verification methods available on the Registry class. Idealy, I want to test on the registry class directly.

like image 817
Marius Avatar asked Mar 18 '10 11:03

Marius


3 Answers

Think of a Registry class like a config file - it doesn't really make sense to test it in isolation, but you might want to test how another class responds to it. In this case, you would test how a Container behaves when given a registry, so you were on the right track by introducing the Container to your test.

In your test, you can request an IDateTimeProvider and assert that the concrete type returned is the type you expect. You can also retrieve 2 instances from the container and assert that they are the same instance (ReferenceEquals) to verify the singleton behavior.

like image 69
Joshua Flanagan Avatar answered Nov 17 '22 05:11

Joshua Flanagan


Within StructureMap a registry is used to generate a PluginGraph; so to unit test a registry you need to check that it's design produces the correct graph. Unfortunately test verification is best done against an internal property, here's a sample:

public interface IFoo {}

public class SomeFoo : IFoo {}

public class FooRegistry : Registry
{
  public FooRegistry()
  {
    For<IFoo>().Use<SomeFoo>();
  }
}

[TestFixture]
public class FooRegistryTests
{
  [Test]
  public void ForIFoo_UseSomeFoo_AsDefaultInstance()
  {
    // Arrange
    var registry = new FooRegistry();

    // Act
    var pluginGraph = registry.Build();
    var iFooPluginFamily = pluginGraph.FindFamily(typeof(IFoo));
    var defaultInstance = iFooPluginFamily.GetDefaultInstance();

    // Assert
    Assert.IsTrue(defaultInstance.UsesConcreteType<SomeFoo>());
  }
}

public static class TestExtensions
{
  public static bool UsesConcreteType<T>(this Instance instance)
  {
    var concreteTypeProperty = typeof (Instance).GetProperty("ConcreteType", BindingFlags.Instance | BindingFlags.NonPublic);
    if (concreteTypeProperty == null || concreteTypeProperty.PropertyType != typeof(Type))
    {
      Assert.Inconclusive("Unable to locate the internal StructureMap.Instance.ConcreteType property");
    }
    var propertyValue = concreteTypeProperty.GetValue(instance, new object[] {}) as Type;

    return typeof (T) == propertyValue;
  }
}

Testing against an internal property is never desirable, but in the case of testing registry's it's been the best approach I've found. The extension method tries to be just smart enough to be able to make tests which rely on it inconclusive if the internal API changes.

like image 26
STW Avatar answered Nov 17 '22 03:11

STW


Check this interesting atircle http://lostechies.com/jimmybogard/2010/01/22/advanced-structuremap-diagnosing-problems/ for example :

[Test]
public void Should_connect_delete_handler_by_registry() 
{
     var container = new Container(new HandlerRegistry());
     var handler = container.GetInstance<IHandler<DeleteEntityCommand<Customer>>>();
     handler.ShouldBeInstanceOf<DeleteEntityCommandHandler<Customer>>(); 
}
like image 2
moi_meme Avatar answered Nov 17 '22 03:11

moi_meme