在我们的代码中,有相当多的日志片段是这样的:
if(logger.isDebugEnabled()) {
logger.debug("...")
}
是否可以配置 SonarQube 以使此类代码块不包含在代码覆盖率分析中?编写测试来覆盖此类调试语句似乎没有多大意义......
我找到了如何:
但是我没有找到一种仅从覆盖率分析中排除代码块的方法。
由于 Sonarqube 可以导入 JaCoCo 覆盖率报告,因此您可以使用名称中包含“
Generated
”的注释,如 nineninesevenfour 在此处解释。
在您的情况下,您可以将日志调用替换为 logDebug()
调用,并且:
@Generated
void logDebug(String message) {
if(logger.isDebugEnabled()) {
logger.debug("...")
}
}
使用对于将日志记录语句封装在单独的方法中对性能的影响,这是一个合理的担忧。
@Generated
是一个不错的技巧。但要注意,在记录参数检索成本较高的消息时不要使用此选项,因为将其封装在方法中需要始终计算参数,从而违背了在检索和记录它们之前检查isDebugEnabled()
的目的。
在 Java 中,方法参数在调用方法之前进行评估。因此,如果将日志记录调用封装在方法内,则无论
logger.isDebugEnabled()
返回 true 还是 false,都将始终执行生成日志消息所需的任何昂贵的计算。例如,请考虑以下事项:
@Generated
void logDebug(String message) {
if (logger.isDebugEnabled()) {
logger.debug(message);
}
}
// Calling the method
logDebug(expensiveComputation()); // expensiveComputation() will always execute
无论日志记录级别如何,expensiveComputation()
方法都会执行,这可能会导致性能问题。一种可能的替代方案是延迟评估参数。
您可以传递生成消息的供应商函数,而不是直接传递消息。
@Generated
void logDebug(Supplier<String> messageSupplier) {
if (logger.isDebugEnabled()) {
logger.debug(messageSupplier.get());
}
}
然后,像这样调用该函数:
logDebug(() -> expensiveComputation());
使用 Supplier<String>
的替代方案与评论的关注点非常吻合,确保仅在启用调试时才进行昂贵的计算,并保留原始
isDebugEnabled()
检查的性能优势。
@Generated
void logDebug(Supplier<String> messageSupplier) {
if (logger.isDebugEnabled()) {
logger.debug(messageSupplier.get());
}
}
logDebug
方法用
@Generated
注释,以排除在代码覆盖率分析之外。它接受
Supplier<String>
来延迟日志消息的可能昂贵的计算,直到确认调试日志记录已启用。因此保留了原始
isDebugEnabled()
检查的性能优化。
1)使用任何模拟框架示例 Mockito、Powermockito、PowerMock 等模拟这些记录器。在适用的情况下在测试类中使用相同的模拟代码
2)将logback-test.xml(或您使用的任何日志框架的日志配置文件)保留在类路径中,并设置较低的日志级别(如Trace)。因此让测试类加载记录器以打印这些语句。
这将有助于显示有关测试用例如何执行语句的详细信息