如何在通过测试的单元测试中验证日志消息?
How to verify log message in Unit testing for a passing test?
我正在测试端点。我需要弄清楚如何让我的 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);
我的测试设置为出现后一条消息。我怎样才能通过测试?
您可以使用表达式来匹配 logText
字符串
,而不是仅将 null
值传递给 LogInfo
方法的 Setup
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 了解更多详情
如果您在 .NET 中使用 LogError
、LogDebug
、LogWarning
等方法,这些方法是扩展方法,现在的问题是您无法模拟扩展方法.所以你需要做的是模拟当你调用LogError
、LogDebug
、LogWarning
等方法时实际调用的底层方法。
实际上,所有这些方法都会调用 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);
我正在测试端点。我需要弄清楚如何让我的 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);
我的测试设置为出现后一条消息。我怎样才能通过测试?
您可以使用表达式来匹配 logText
字符串
null
值传递给 LogInfo
方法的 Setup
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 了解更多详情
如果您在 .NET 中使用 LogError
、LogDebug
、LogWarning
等方法,这些方法是扩展方法,现在的问题是您无法模拟扩展方法.所以你需要做的是模拟当你调用LogError
、LogDebug
、LogWarning
等方法时实际调用的底层方法。
实际上,所有这些方法都会调用 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);