我试图测试我的IEventProcessor的实现。但是,我很难,因为实际上不可能模拟PartitionContext类(https://msdn.microsoft.com/en-us/library/microsoft.servicebus.messaging.partitioncontext.aspx)。
例如,我无法验证是否已正确调用CheckpointAsync()方法,因为ICheckpointer接口是内部的,实际方法不是虚拟的。此外,我不能注入我自己的ICheckpointManager实例,因为允许它的构造函数是内部的。
将所有内容制作成内部的设计决策是什么,这将允许我模拟这个类?
要么这是非常糟糕的设计,要么我错过了一些东西。
是的,测试这个是很多工作。这是做什么的。
所以你创建了一个包装器:
public interface ICheckPointer
{
Task CheckpointAsync(PartitionContext context);
}
public class CheckPointer : ICheckPointer
{
public Task CheckPointAsync(PartitionContext context)
{
return context.CheckpointAsync();
}
}
在单元测试方法中,您现在可以模拟接口并检查是否调用了CheckPointAsync
。
你现在的IEventProcessor
实现应该接受ICheckPointer
的一个实例:
public class SampleEventProcessor : IEventProcessor
{
private ICheckPointer checkPointer;
public SampleEventProcessor(ICheckPointer checkPointer)
{
this.checkPointer = checkPointer;
}
public Task OpenAsync(PartitionContext context)
{
return Task.FromResult<object>(null);
}
public async Task ProcessEventsAsync(PartitionContext context, IEnumerable<EventData> events)
{
...
await checkPointer.CheckpointAsync(context);
}
public async Task CloseAsync(PartitionContext context, CloseReason reason)
{
return Task.FromResult<object>(null);
}
}
您将需要IEventProcessorFactory
的实现来注入ICheckPoint
接口:
internal class SampleEventProcessorFactory : IEventProcessorFactory
{
private readonly ICheckPointer checkPointer;
public SampleEventProcessorFactory (ICheckPointer checkPointer)
{
this.checkPointer = checkPointer;
}
public IEventProcessor CreateEventProcessor(PartitionContext context)
{
return new SampleEventProcessor(checkPointer);
}
}
并像这样创建EventProcessor:
await host.RegisterEventProcessorFactoryAsync(new SampleEventProcessor(new CheckPointer()));
在单元测试中你现在可以做类似的事情(基于NSubstitute):
var mock = Substitute.For<ICheckPointer>();
var sample = new SampleEventProcessor(mock);
await sample.ProcessEventsAsync(new PartitionContext(), null);
mock.Received().CheckPointAsync(Arg.Any<PartitionContext>());
警告:没有编译代码,因此可能存在一些语法错误。至少它应该给你一个如何进行的基本想法。