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

时间:2018-09-21 08:31:31

标签: unit-testing mocking nsubstitute

场景

我想检查某个组件(sut)在特定情况下是否记录错误。将ILogger接口构造函数注入到组件中,并且Error方法具有4个重载。

因此,我在Arrange中创建了一个ILogger模拟,并在Act中使用了它。

我不应该期望sut正在使用哪个过载,只是希望期望并检查是否调用了任何过载。 (那将是白盒,并且期望远远超出功能规格。)

问题

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

有什么简单的方法可以做到这一点吗?

(示例)

[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>());
}

1 个答案:

答案 0 :(得分:2)

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)这样的助手可以访问参数?)