Tobias Moe Thorstensen
Tobias Moe Thorstensen

Reputation: 8981

Unit Testing code which uses autofac as IoC-container

I have a simple framework which will allow "everything" subscribe to events given that a "Guard" has been passed. The syntax for declaring it looks like this:

public class MyObject : ICanHandle<MySuperAwesomeEvent, GivenYouAreLeetGuard> { .... }

The guard can be created two different ways. Either by registering in the container using this extensions method

public static void RegisterCommandGuard<TCommandGuard>(this ContainerBuilder builder)
  where TCommandGuard : IExecuteGuard
 {
     var type = typeof(TCommandGuard);
     var typeName = type.FullName;
     builder.RegisterType<TCommandGuard>().Named(typeName, type);
 }

Or it will be created by using reflection during the resolvement of this component in my framework.

public bool CanExecute(object message)
{
    object resolvedType = null;
    var name = CanExecuteGuard.FullName;
    if(!_componentContext.TryResolveNamed(name, typeof(IExecuteGuard), out resolvedType))
    {
        try
        {
            resolvedType = (IExecuteGuard)Activator.CreateInstance(CanExecuteGuard);
        }
        catch (Exception e)
        {
            throw new Exception($"Cannot locate {name} in container nor create an instance of it. See inner exception:", e);
        }
    }

    return ((IExecuteGuard)resolvedType).CanExecute(message);
}

Running this in my application works as I expect, but in my tests I'm not able to resolve any of the "Guards".

[Fact]
public void EventAggregator_GivenGuardWithDependencies_ShouldFireEventToAllSubscribers()
{
    var containerBuilder = new ContainerBuilder();
    containerBuilder.RegisterType<UserRepository>().As<IUserRepository>();
    containerBuilder.RegisterCommandGuard<MustBeAdminGuard>();
    var container = containerBuilder.Build();

    using (var lifeTimeScope = container.BeginLifetimeScope())
    {
        var eventAggregator = new ExtendedEventAggregator(lifeTimeScope);
        var @object = new ObjectWhichHandlesUsers();
        eventAggregator.Subscribe(@object);
        eventAggregator.PublishOnUIThread(new FireEmployeeCommand(userId: 1, userToFireId: 5));
        @object.UserIds.Should().HaveCount(6);
    }
}

The TryResolveNamed method in the IComponentContext will never find my registered guard. Looking at the debugger, I can clearly see that "something" is registered somehow

enter image description here

What am I doing wrong here? Other suggestions on how to improve the code is also appricated with a comment. Thanks!

EDIT:

During debugging of my unit test, I tried to check wheter or not the Guard had been registered by typing the following in the Immidiate Window in Visual Studio:

lifeTimeScope.IsRegisteredWithName("Caliburn.Micro.Demo.Tests.MustBeAdminGuard",typeof(MustBeAdminGuard))

And this query returns true. What is the real difference by passing in the IComponentContext instead of the ILifeTimeScope? I thought this interface only exposed a subset of the methods exposed by ILifeTimeScope..

Upvotes: 0

Views: 224

Answers (1)

Paweł G&#243;rszczak
Paweł G&#243;rszczak

Reputation: 574

i have test smth similar on my own, and it is working, but i know where is your problem, you have registered type MustBeAdminGuard and you want to resolve different type IExecuteGuard, so don't expect that it will work like this :)

So to solve it you have to change registering part in class RegisterCommandGuard. You have two possibilities choose which you want

//1. looks better
builder.RegisterType<TCommandGuard>().Named<IExecuteGuard>(typeName);

//2.
builder.RegisterType<TCommandGuard>().Named(typeName, typeof(IExecuteGuard));

Let me know if it solved your problem, it have to ^^, since i have tested it on common example.

Upvotes: 1

Related Questions