如何检查称为 NSubstitute 的多个重载中的任何一个

How to check any of multiple overloads called NSubstitute

场景

我想检查组件 (sut) 是否在特定条件下记录错误。注入组件的ILogger接口构造函数,Error方法重载4次

所以我在 Arrange 中创建了一个 ILogger mock 并在 Act 中使用它。

我不应该期待 sut 使用的是哪个重载,只是想期待并检查是否调用了任何重载。 (那将是非常白盒的,并且期望远远超过功能规范。)

问题

目前我的结论是我不能使用 .Received 而是我必须为所有 4 个重载安装回调,并在其中设置一个变量,并在断言部分检查该变量。

有什么简单的方法可以做到我错过的吗?

(示例)

[TestMethod]
public void ShouldLogErrorIfEmailIsInvalid2()
{
    // Arrange
    var testEmailAddress = "dummy";

    //var mock = new Mock<IEMailValidator>();
    var validator = Substitute.For<IEMailValidator>();
    validator.Validate(Arg.Any<string>()).Returns(false);
    var logger = Substitute.For<ILogger>();

    var sut = new CustomerController(validator, logger);

    var customer = new Customer() { Email = testEmailAddress };

    // Act
    sut.Post(customer);

    // Assert
    // *** Here I do not want to expect a specific overload of Error, instead any of the 4 overloads satisfies the expectation
    logger.Received(1).Error(Arg.Is<string>( m => m.ToLower().Contains("email")), Arg.Any<object>());
}

NSubstitute 对此没有内置语法,但可以查询所有 ReceivedCalls() 并对此手动断言。

例如:

var errorCalls = logger.ReceivedCalls()
    .Where(x => x.GetMethodInfo().Name == nameof(logger.Error))
    .Where(x => (x.GetArguments()[0] as string).ToLower().Contains("email"));

Assert.AreEqual(1, errorCalls.Count());

如果这是您经常需要的东西,您可以实现一些辅助方法并将其打包成我认为相当简洁的东西。 (也许 static void ReceivedCallToAny(this object substitute, string methodName, Func<object[], bool> requiredArgs) 有一些像 T GetItemAs<T>(object[] items) 这样的助手来访问参数?)