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.
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.
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.
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>>();
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With