【问题标题】:Assert on received ILogger calls using NSubstitute doen't matches使用 NSubstitute 断言收到的 ILogger 调用不匹配
【发布时间】:2020-04-05 21:08:18
【问题描述】:

我在为 ILogger 调用匹配实现测试时遇到问题,当测试方法抛出异常时,我真的不明白是什么原因。

这是我的测试方法的样子:

public async Task My_test_method()
{
    //Arrange

    var _logger = Substitute.For<ILogger<MyType>>();
    var _mockedInnerService = Substitute.For<IMockedInnerService>();
    var _testedService = new TestedService(_mockedInnerService, _logger);

    var errorMessage = "Some problem";
    _mockedInnerService
        .When(async _self => await _self.SomeMethod(Arg.Any<string>(), Arg.Any<string>()))
        .Do(_self => throw new Exception(errorMessage));
    var expectedMessage = $"Error: {errorMessage}";
    var methodParameters = new List<Guid>() { Guid.NewGuid() };

    //Act
    var results = await _testedService.TestedCall(methodParameters);

    //Assert
    await _mockedInnerService
        .Received(1)
        .SomeMethod(Arg.Any<string>(), Arg.Any<string>());
    results
        .Should()
        .BeEmpty();
    _logger
        .Received(1)
        .LogError(Arg.Is<string>(message => message == expectedMessage));
}

这就是我测试过的方法的样子:

public async Task<IList<SomeObject>> TestedCall(IList<Guid> ids)
{

    IList<object> results = null;
    try
    {
        units = await _innerService.SomeMethod("arg", "arg");
    }
    catch (Exception e)
    {
        var msg = "Some problem";
        _logger.LogError(msg);
    }

    return results == null
        ? new List<object>()
        : results.Select(s => new SomeObject(s.Id, s.Code)).ToList();
}

测试失败,结果如下:

Message: 
    NSubstitute.Exceptions.ReceivedCallsException : Expected to receive exactly 1 call matching:
        Log<Object>(Error, 0, [null], <null>, Func<Object, Exception, String>)
    Actually received no matching calls.
    Received 1 non-matching call (non-matching arguments indicated with '*' characters):
        Log<Object>(Error, 0, *Some problem*, <null>, Func<Object, Exception, String>)

你们能帮我理解我在这里做错了什么吗?

谢谢

【问题讨论】:

标签: c# unit-testing nsubstitute ilogger


【解决方案1】:

看起来ILogger&lt;T&gt;.LogError(string) 方法实际上是一个扩展方法。这意味着它将在后台转换为不同的调用,即您在输出中看到的Log&lt;Object&gt;(Error, 0, [null], &lt;null&gt;, Func&lt;Object, Exception, String&gt;)。此方法调用可以有额外的参数,对于扩展方法的每次调用,这些参数可能不同,因此在您的实际调用和断言调用之间可能会有所不同。

要修复它,您可能必须对底层方法进行断言,并使用Arg.Any&lt;T&gt;() 使其忽略有问题的参数,这可能是最后的Func&lt;Object, Exception, String&gt; 参数。

【讨论】:

  • 你说的完全正确,它是一种扩展方法。正如您所建议的,我无法使用底层方法 (.Log&lt;Object&gt;()) 获得断言。每次尝试都会导致不匹配的呼叫。我已将断言更改为_logger.ReceivedWithAnyArgs().LogError("Some problem");,它现在正在工作。 =/我对此不满意,但现在它会给我一些时间继续前进。谢谢回答
  • 一旦扩展方法解释了问题,我将其作为答案进行检查。
  • @DiegoRafaelSouza 不确定您已经为底层方法尝试过什么,但也许您可以先尝试使用Arg.Any&lt;T&gt;() 作为 all 参数,如果 确实如此 工作,用你自己的方式来替换你确实想用实际参数一一检查的参数,至少找到导致问题的那个?否则,您可能必须检查扩展方法的实现以查看它是否在做其他事情,这可能比它的价值(假设第三方库)更麻烦,​​除非您将进行大量此类测试。
  • 有关这方面的更多信息,请参阅NSubstitute issue #597
猜你喜欢
  • 1970-01-01
  • 2020-06-26
  • 1970-01-01
  • 2018-03-13
  • 2018-05-28
  • 1970-01-01
  • 2018-02-25
  • 2015-05-09
  • 1970-01-01
相关资源
最近更新 更多