如何测试使用 Schedule 的 NServiceBus 处理程序

How to test an NServiceBus handler that uses Schedule

我正在玩一个实现 IWantToRunWhenBusStartsAndStops 的简单处理程序,一开始,它会安排一个任务,如下所示:

    public void Start()
    {
        _schedule.Every(TimeSpan.FromSeconds(5), Moo);
    }

_schedule 通过构造函数注入。我正在尝试编写的测试是确保在处理程序启动时安排任务。但是我找不到模拟 Schedule 的方法,因为它没有无参数构造函数,也没有实现接口。我尝试用模拟的 IBuilder 创建它的实际实例,但无法弄清楚要在 IBuilder 上设置什么期望。另外,我查看了源代码以了解他们是如何测试 Schedule 但看起来我们使用的是早期版本(v5.0.0 通过 nuget),因为我们没有出现 DefaultScheduler成为他们在当前测试中使用的内容。

事实上,NServiceBus 团队已经用 unit/acceptance 测试覆盖了调度程序,即当您的处理程序执行时,无需检查任务是否实际调度。相反,您可能希望对处理程序本身进行单元测试,从而检查是否已调用 scheduler.Every() 。这是您的单元测试的简单示例:

[TestClass]
public class Tests
{
    [TestMethod]
    public void When_executing_handler_the_task_should_be_scheduled()
    {
        //arrange
        var scheduler = new FakeSheduler();

        //act
        var handler = new TestHandler(scheduler);
        handler.Start();

        //assert
        Assert.IsTrue(scheduler.WasCalled);
    }
}

处理程序本身:

class TestHandler: IWantToRunWhenBusStartsAndStops
{
    readonly IMyScheduler _scheduler;

    public TestHandler(IMyScheduler scheduler)
    {
        _scheduler = scheduler;
    }

    public void Start()
    {
        _scheduler.Every(TimeSpan.FromSeconds(5), () => { });
    }

    public void Stop() { }
}

最后,您必须从 NServiceBus 调度程序的直接使用中抽象出来,以使其可测试,想法如下:

interface IMyScheduler
{
    void Every(TimeSpan interval, Action action);
}

//your real implementation
class MySheduler: IMyScheduler
{
    readonly Schedule _schedule;

    public MySheduler(Schedule schedule)
    {
        _schedule = schedule;
    }

    public void Every(TimeSpan interval, Action action)
    {
        _schedule.Every(TimeSpan.FromSeconds(5), () => { });
    }
}

//fake for the testing
class FakeSheduler: IMyScheduler
{
    public bool WasCalled { get; set; }

    public void Every(TimeSpan interval, Action action)
    {
        WasCalled = true;
    }
}