使用autofac作为IoC容器的单元测试代码

时间:2018-12-19 07:28:28

标签: c# unit-testing autofac

我有一个简单的框架,该框架将允许“一切”订阅事件,前提是已传递“警卫队”。声明它的语法如下:

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

可以通过两种不同方式创建防护。通过使用此扩展方法在容器中注册

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);
 }

或者它将通过解析在我的框架中的组件期间创建。

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);
}

在我的应用程序中运行此程序符合我的预期,但是在我的测试中,我无法解决任何“防护措施”。

[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);
    }
}

IComponentContext中的TryResolveNamed方法将永远找不到我的注册后卫。看着调试器,我可以清楚地看到“某物”是以某种方式注册的

enter image description here

我在这里做错了什么?有关如何改进代码的其他建议也附有评论。谢谢!

编辑:

在调试单元测试期间,我尝试通过在Visual Studio的“模拟”窗口中键入以下命令来检查是否已注册Guard,

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

此查询返回true。通过传递IComponentContext而不是ILifeTimeScope的真正区别是什么?我以为该接口只公开了ILifeTimeScope公开的方法的子集。

1 个答案:

答案 0 :(得分:0)

我自己进行了类似的测试,并且可以正常工作,但是我知道您的问题在哪里,您已经注册了MustBeAdminGuard类型,并且您想解析其他类型的IExecuteGuard,所以不要指望它会像这样工作:)

因此,要解决此问题,您必须更改RegisterCommandGuard类中的注册部分。您有两种可能性选择想要的

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

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

让我知道它是否可以解决您的问题,必须^^,因为我已经在常见示例中对其进行了测试。