断言在最终调用之前发生了多个无序调用

Assert that multiple unordered calls occur before a final call

我有一项服务

  1. 调用实现特定接口的每个已注册 class (IUnorderedService)
  2. 然后最终调用另一个服务 (IFinalService)

我想编写一个测试,断言我的服务以无特定顺序调用每个 IUnorderedService,然后调用 IFinalService使用FakeItEasy,有什么办法吗?

我的实现看起来像这样(大大简化):

public class MyService
{
    private readonly IFinalService finalService;

    private readonly IEnumerable<IUnorderedService> unorderedServices;

    public MyService(
        IFinalService finalService,
        IEnumerable<IUnorderedService> unorderedServices)
    {
        this.finalService = finalService;
        this.unorderedServices = unorderedServices;
    }

    public void Execute()
    {
        foreach (var unorderedService in this.unorderedServices)
        {
            unorderedService.Execute();
        }

        this.finalService.Execute();
    }
}

我的测试方法看起来像这样

public void ShouldCallUnorderedService_BeforeCallingFinalService()
{
    // Arrange
    ...

    // Act
    myService.Execute();

    // Assert
    foreach (var unorderedService in unorderedServices)
    {
        A.CallTo(() => unorderedService.Execute()).MustHaveHappenedOnceExactly();
    }

    // Should be asserted that this call occurs after all of the above calls have occurred.
    A.CallTo(() => finalService.Execute()).MustHaveHappenedOnceExactly();
}

我尝试过 A.CallTo().Then() 语法,它对大多数用途都非常有用,但我没有看到在有序调用之前断言多个无序调用发生的方法。

您可以将 A.CallTo().Then() 放入您的 foreach

    foreach (var unorderedService in unorderedServices)
    {
        A.CallTo(() => unorderedService.Execute()).MustHaveHappenedOnceExactly()
         .Then(A.CallTo(() => finalService.Execute()).MustHaveHappenedOnceExactly()
    }

所以您正在检查对无序服务的每次调用都发生在对最终服务的调用之前。不幸的是,这不是批量检查,但我认为最终结果仍将证明代码的正确性

对于这种情况,FakeItEasy 中没有直接内置任何内容。一种选择是intercept the calls。然后您可以验证订单是否如您所愿。呼叫拦截功能(我相信)很少使用,因此这可能不太容易理解,但值得追求。

然后我考虑利用 Fake 上的“callback”或 Invokes 功能来记录虚假呼叫是否应该是最终的,然后在结束时验证设置测试:

[Fact]
public void ShouldCallUnorderedService_BeforeCallingFinalService()
{
    var lastKindOfService = "none";

    var unorderedServices = new [] {
        A.Fake<IUnorderedService>(),
        A.Fake<IUnorderedService>(),
        A.Fake<IUnorderedService>(),
    };

    foreach (var unorderedService in unorderedServices)
    {
        A.CallTo(() => unorderedService.Execute()).Invokes(() => lastKindOfService = "unordered");
    }

    var finalService = A.Fake<IFinalService>();
    A.CallTo(() => finalService.Execute()).Invokes(() => lastKindOfService = "final");

    var service = new MyService(finalService, unorderedServices);
    service.Execute();

    foreach (var unorderedService in unorderedServices)
    {
        A.CallTo(() => unorderedService.Execute()).MustHaveHappenedOnceExactly();
    }
    A.CallTo(() => finalService.Execute()).MustHaveHappenedOnceExactly();

    lastKindOfService.Should().Be("final");
}

当然这可以用辅助方法或状态枚举来美化。如果有任何异步,您可能需要序列化更新。