8

I have IWindsorContaner which exists for the whole application lifetime. For Unittests it is possible to register mocks/stubs, etc. under their Type. When the test is finished and the fixture is disposed the registered components in forthe test are remove with a self created method called "Unregister".

Now, I want to update to the latest Castle version which is 3.0. According to the 3.0 release notes something like

public void Unregister(string contextName, string registrationName)
{
   IWindsorContainer context = GetOrCreateContext(contextName);
   context.Kernel.RemoveComponent(registrationName);
}

is not possible anymore, because the IKernel.RemoveComponent method has been removed. The description to fix this is not really sufficient ("Try utilizing IHandlerSelectors.").

A simplified version of the fixture I use for unittests:

public sealed class DependencyInjectionFixture : IDisposable
{
  private Stack<Type> registeredTypes = new Stack<Type>();

  // Registering of mocks/stubs, etc
  public void RegisterSingleton<T>(T singleton, string objectName)
  {
     registeredTypes.Push(typeof(T));

     IWindsorContainer context = GetOrCreateContext(contextName);

     context.Register(Component.For(typeof(T))
                               .Named(objectName)
                               .Instance(singleton)
                               .LifeStyle.Singleton);
  }

  // Called when tests ends
  public void Dispose()
  {
     IWindsorContainer context = GetOrCreateContext(contextName);

     while (registeredTypes.Count > 0)
        context.Kernel.RemoveComponent(CSApplicationContext.GetRegistrationNameFor(registeredTypes.Pop()));
  }

}

How can I remove components with Castle 3.0?

Antineutrino
  • 1,093
  • 3
  • 10
  • 26

2 Answers2

2

Instead of trying to remove all components, just create a new IWindsorContainer and bind that to whatever GetOrCreateContext is checking against. Then you'll have a fresh new container that has nothing bound to it.

eouw0o83hf
  • 9,438
  • 5
  • 53
  • 75
  • 2
    Of course this would work. But this would also require a lot of code changes in many dependent software projects. I found a solution with putting an holder object to the container instead of the real one. But the more I think about it Castle does not really seem to be the right IoC container for unittests, is it? – Antineutrino Mar 12 '12 at 17:39
  • For all unit tests that I have written to this point, Castle has been exactly the perfect IoC container for unit tests. Why do you need to clear all of the registered entities anyway? – eouw0o83hf Mar 13 '12 at 14:30
  • 1
    Because each unit test registers its own mocks. If they are not removed the next unit test would be using the wrong mocks. So there's code in the IDisposable.Dispose method of the Ioc test fixture that removes all components. – Antineutrino Mar 19 '12 at 18:29
  • 2
    Then each of the tests should probably have its own `IWindsorContainer`. Maybe you need to do away with `GetOrCreateContext()` for unit testing and just manually handle that container object. – eouw0o83hf Mar 19 '12 at 18:36
  • Yes, but this would require a lot of changes in many dependends software products we have. So I guess the workaround is the only acceptable solution. – Antineutrino Mar 20 '12 at 13:07
  • 8
    Your answer does not explain the way to remove a component – Mert Akcakaya Sep 17 '13 at 09:06
1

I know Im late to the game but I came up against this same issue. My problem was that due to the size of the application, first run of Castle Windsor was very slow (1s+) and to create a new context for each and every test was becoming onerous (600 tests, 5min wait time on Castle Windsor only)

I based my solution on How to remove component in Castle Windsor 3.0?

    public class WindsorHandlerOverride : IHandlerSelector
{
    private Dictionary<Type, object> definedTypeBehaviours;

    public bool HasOpinionAbout(string key, Type service)
    {
        return definedTypeBehaviours.IsNotNullAndAny(t => t.Key == service);
    }

    public IHandler SelectHandler(string key, Type service, IHandler[] handlers)
    {
        var theValue = definedTypeBehaviours[service];
        return new WindsorSimpleHandler {TheValue = theValue};
    }

    public void CleanUp()
    {
        definedTypeBehaviours = null;
    }

    public void OverrideBehaviour(Type type, object value)
    {
        if (definedTypeBehaviours == null)
        {
            definedTypeBehaviours = new Dictionary<Type, object>();
        }
        definedTypeBehaviours.Add(type, value);
    }
}

and

    public class WindsorSimpleHandler : IHandler
{
    public object TheValue { get; set; }
    public ComponentModel ComponentModel { get; set; }
    public HandlerState CurrentState { get; set; }

    public bool CanResolve(CreationContext context, ISubDependencyResolver contextHandlerResolver, ComponentModel model,
        DependencyModel dependency)
    {
        return true;
    }

    public object Resolve(CreationContext context, ISubDependencyResolver contextHandlerResolver, ComponentModel model,
        DependencyModel dependency)
    {
        return TheValue;
    }

    public object Resolve(CreationContext context)
    {
        return TheValue;
    }...

Then wherever you set up windsor

        WindsorOverrider = new WindsorHandlerOverride();
        container.Kernel.AddHandlerSelector(WindsorOverrider);

And when you want to override castle windsor default behaviour in test

WindsorOverrider.OverrideBehaviour(typeof(IService), mock.Object);

And on test tear down call

WindsorOverrider.CleanUp();
Smilie
  • 2,935
  • 1
  • 13
  • 3