繁体   English   中英

如何使用SimpleInjector 3+对装饰器注册进行单元测试?

[英]How to unit test decorator registrations using SimpleInjector 3+?

在这里跟进一个较旧的问题 说我有以下注册:

container.Register(typeof(IHandleCommand<>), _handlerAssemblies, Lifestyle.Transient);
container.RegisterDecorator(typeof(IHandleCommand<>),
  typeof(MetricsCommandHandlerWrapper<>), Lifestyle.Singleton);

MetricsCommandHandlerWrapper的定义如下:

public class MetricsCommandHandlerWrapper<T> : IHandleCommand<T> where T: ICommand
{
    private readonly ICollectMetrics _metrics;
    private readonly Func<IHandleCommand<T>> _handlerFactory;

    public MetricsCommandHandlerWrapper(ICollectMetrics metrics,
      Func<IHandleCommand<T>> handlerFactory)
    {
      _metrics = metrics;
      _handlerFactory = handlerFactory;
    }

    public async Task HandleAsync(T command)
    {
        // code to record metrics around command handling which eventually invokes
        await _handlerFactory().HandleAsync(command).ConfigureAwait(false);
    }
}

如何编写一个单元测试来断言实际的decoratee处理程序是否已经注册了Transient生活方式?

我已经尝试编写根并检查注册的闭合IHandleCommand<FakeCommand>类型,它按预期显示了MetricsCommandHandlerWrapper<FakeCommand>ImplementationType 在该注册上调用GetRelationships()会显示其2个依赖项ICollectMetrics和我感兴趣的依赖项Func<IHandleCommand<FakeCommand>>工厂委托,它被注册为Singleton 但是,在该工厂委托上调用.Dependency.GetInstance()会抛出实例生成器返回null的异常。

有没有办法断言内部decoratee注册为Transient ,如果是,如何?

使用Func<T>延迟了对象图的构建,并且从诊断系统的角度来看,图表在那时停止。 因此,不可能进行此分析。

但是,您可以选择在应用程序中进行一些小的更改以允许测试装饰器,而不是完全依赖于Simple Injector的内部。

你可以做的是在装饰器上实现IDecorator抽象:

public interface IDecorator {
    object Decoratee { get; }
}

现在每个装饰器都可以实现这个接口。 对于MetricsCommandHandlerWrapper<T> ,它可能如下所示:

public class MetricsCommandHandlerWrapper<T> : IHandleCommand<T>, IDecorator where T: ICommand
{
    private readonly ICollectMetrics _metrics;
    private readonly Func<IHandleCommand<T>> _handlerFactory;

    public MetricsCommandHandlerWrapper(ICollectMetrics metrics,
      Func<IHandleCommand<T>> handlerFactory) {
      _metrics = metrics;
      _handlerFactory = handlerFactory;
    }

    public object Decoratee { get { return _handlerFactory(); }

    public async Task HandleAsync(T command) { ... }
}

IDecorator接口之上,您可以定义一个简单的扩展方法:

public static IEnumerable<Type> GetDecoratorChain(this IDecorator decorator) {
    while (decorator != null) {
        yield return decorator.GetType();
        decorator = decorator.Decoratee as IDecorator;
    }
}

在单元测试中,您现在可以解析处理程序并询问应用装饰器的列表。 使用此列表,您可以验证装饰器是否以正确的顺序应用。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM