【问题标题】:How to verify log message in Unit testing for a passing test?如何在单元测试中验证日志消息以通过测试?
【发布时间】:2020-05-29 17:02:23
【问题描述】:

我正在测试一个端点。我需要弄清楚如何使用我的 loggerMock 让测试通过。以下是我目前设置测试的方式:

public void GetExceptionReportSessionData_Returns200OK()
        {
            //Arrange 
            var response = new RetrieveExceptionReportSessionDatesResponse
            {
                RetrieveExceptionReportSessionDatesResult = string.Empty
            };
            var serviceClient = new Mock<WorkflowService.WorkflowService>();      
            serviceClient
                .Setup(x => x.RetrieveExceptionReportSessionDatesAsync(It.IsAny<RetrieveExceptionReportSessionDatesRequest>()))
               .ReturnsAsync(response);

            var loggerMock = new Mock<ILogger>();
            loggerMock.Setup(x => x.LogInfo(null));

            var controller = new ExceptionReportController(loggerMock.Object);

            var ctx = new ControllerContext() { HttpContext = new DefaultHttpContext() };
            ctx.HttpContext.Request.Headers["token"] = "fake_token_here"; //Set header
            controller.ControllerContext = ctx;

            //Act
            var result = controller.GetExceptionReportSessionData();

            //Assert
            var viewResult = Assert.IsType<OkObjectResult>(result);
            Assert.Equal(StatusCodes.Status200OK, viewResult.StatusCode);


        }

这是在返回 200 时在端点中设置记录器的方式:

if (result != null && result.ExceptionReportLines != null && result.ExceptionReportLines.Count > 0)
            {
                logText = LogFormatter.Format(
                                WebUtilities.GetUser((ClaimsIdentity)HttpContext.User.Identity),
                                startTime, DateTime.Now, Privilege.ViewOrderExceptionReport,
                                "Get Exception Report", "Exception Report retrieved successfully.");
                logger.LogInfo(logText);
            }
            else
            {
                logText = LogFormatter.Format
                                (WebUtilities.GetUser((ClaimsIdentity)HttpContext.User.Identity),
                                startTime, DateTime.Now, Privilege.ViewOrderExceptionReport,
                                "Get Exception Report", "Exception report is empty for the given report filters.");
                logger.LogWarn(logText);
            }

            return Ok(result);

我的测试已设置为显示后一条消息。我怎样才能让测试通过?

【问题讨论】:

  • 出于好奇,LogInfo 和 LogWarn 是从哪里来的?它们不是 MS 扩展...

标签: c# unit-testing asp.net-core moq xunit


【解决方案1】:

您可以使用表达式来匹配logText 字符串,而不是将null 值传递给SetupSetup 字符串

loggerMock
    .Setup(x => x.LogInfo(It.Is<string>(s => s.Contains("Exception Report retrieved successfully."))))
    .Verifiable();

并在Assert 步骤中使用Verify()

loggerMock.Verify();

它确保loggerMock 中的LogInfo() 方法被调用,字符串匹配指定的表达式。查看Moq wiki 中的matching arguments 了解更多详情

【讨论】:

    【解决方案2】:

    如果您在 .NET 中使用 LogErrorLogDebugLogWarning 等方法,这些方法是扩展方法,现在的问题是您无法模拟扩展方法。所以你需要做的是模拟当你调用LogErrorLogDebugLogWarning等方法时实际调用的底层方法。

    实际上,所有这些方法都会调用Log 方法,因此您需要模拟Log 方法。

    Log方法的定义如下

      void Log (this ILogger logger, LogLevel logLevel, EventId eventId, Exception exception, string message, params object[] args)
    

    您可以使用LogWarning 扩展方法模拟Log 方法,如下所示

    [Fact]
    public void VerifyLogWarning()
    {
        // Arrange
        var loggerMock = new Mock<ILogger<MyClass>>();
        var myclass = new MyClass(loggerMock.Object);
    
        // Act
        myclass.TestMethod();
    
        // Assert
        loggerMock.Verify(
            x => x.Log(
                It.Is<LogLevel>(l => l == LogLevel.Warning),
                It.IsAny<EventId>(),
                It.Is<It.IsAnyType>((v, t) => true),
                It.IsAny<Exception>(),
                It.Is<Func<It.IsAnyType, Exception, string>>((v, t) => true)), Times.Once);
    }
    

    在上面的代码中,我们正在验证我们是否在TestMethod() 调用中调用了一次LogWarning

    您还可以验证日志警告消息如下

     // Assert
        loggerMock.Verify(
            x => x.Log(
                It.Is<LogLevel>(l => l == LogLevel.Warning),
                It.IsAny<EventId>(),
                It.Is<It.IsAnyType>((v, t) =>  v.ToString() == "LogWarning Message......"),
                It.IsAny<Exception>(),
                It.Is<Func<It.IsAnyType, Exception, string>>((v, t) => true)), Times.Once);
    

    【讨论】:

      猜你喜欢
      • 2018-12-17
      • 2019-03-25
      • 2014-08-19
      • 2016-04-30
      • 2021-10-17
      • 2022-11-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多