18
votes

My current understanding of Castle Windsor registration is that one can only validate registration by calling Resolve on a root component. But since windsor's component model knows each component's dependencies, it should be possible to test that all dependencies can be satisfied without actually instantiating anything. The main reason for wanting to do this is to have a unit test for registration that doesn't require me to stub components that call external resources on start-up.

For example. I have a class Root that has a dependency on IChild:

public class Root : IRoot
{
    private IChild child;

    public Root(IChild child)
    {
        this.child = child;
    }
}

If I register Root as IRoot, but don't register an IChild. When I call resolve like this:

var container = new WindsorContainer().Register(
    Component.For<IRoot>().ImplementedBy<Root>()
    );

container.Resolve<IRoot>();

I get an error:

MyNamespace.Root is waiting for the following dependencies: 

Services: 
- MyNamespace.IChild which was not registered. 

Is there something like:

container.TestResolve<IRoot>();

That would walk the dependency graph and check that all dependencies can be satisfied, but which doesn't actually instantiate anything?

1

1 Answers

29
votes

OK, It is possible. Thanks to Krzysztof Koźmic for showing me how. Not immediately obvious, but you can use Windsor's diagnostic subsystem to raise potential problems with registration. I've put together a little static method that throws if there are any misconfigured components:

private static void CheckForPotentiallyMisconfiguredComponents(IWindsorContainer container)
{
    var host = (IDiagnosticsHost)container.Kernel.GetSubSystem(SubSystemConstants.DiagnosticsKey);
    var diagnostics = host.GetDiagnostic<IPotentiallyMisconfiguredComponentsDiagnostic>();

    var handlers = diagnostics.Inspect();

    if (handlers.Any())
    {
        var message = new StringBuilder();
        var inspector = new DependencyInspector(message);

        foreach (IExposeDependencyInfo handler in handlers)
        {
            handler.ObtainDependencyDetails(inspector);
        }

        throw new MisconfiguredComponentException(message.ToString());
    }
}

You can use it like this:

var container = new WindsorContainer().Register(
    Component.For<IRoot>().ImplementedBy<Root>()
    );

CheckForPotentiallyMisconfiguredComponents(container);

In this case I get a MisconfiguredComponentException with this message:

'WindsorSpikes.Root' is waiting for the following dependencies:
- Service 'WindsorSpikes.IChild' which was not registered.

WindsorSpikes.MisconfiguredComponentException:
'WindsorSpikes.Root' is waiting for the following dependencies:
- Service 'WindsorSpikes.IChild' which was not registered.

See the castle documentation for more details on the diagnostic subsystem:

http://stw.castleproject.org/Default.aspx?Page=Debugger-views&NS=Windsor