10

我们正在使用带有 Jacoco maven 插件 0.7.4 的 SonarQube 5.1,并且我们所有的 slf4j 日志记录语句,例如log.debug('Something happened')显示只有 2 个分支中的 1 个被覆盖。我知道这是因为 slf4j 在内部做了一个if debug,这很好,但我们不希望这会影响我们的数字。我们对测试 slf4j 不感兴趣,我们宁愿不为不同的日志记录级别多次运行每个测试。

那么,我们如何告诉 Sonar 和/或 Jacoco 将这些行排除在覆盖范围之外呢?它们都具有可配置的文件排除项,但据我所知,这些仅用于将您自己的类排除在覆盖范围之外(使用目标目录),而不是导入的库。无论如何,我尝试添加groovy.util.logging.*'到排除列表,但它没有做任何事情。

logger.isDebugEnabled() 正在杀死我的代码覆盖率。我打算在运行 cobertura 时将其排除在外,并建议对于 Cobertura,应使用“忽略”属性而不是“排除”。我在设置或文档中看不到 Jacoco 或 Sonar 的类似内容。

编辑:在运行 Jacoco 覆盖之后附加来自 Eclipse 的示例图像(Sonar 在其 GUI 中显示相同的内容)。这是来自我们的一个类的实际代码。 Jacoco 分支覆盖 slf4j 日志记录

编辑 2:我们正在使用 Slf4j 注释。这里的文档: http ://docs.groovy-lang.org/next/html/gapi/groovy/util/logging/Slf4j.html

此本地转换使用 LogBack 日志记录为您的程序添加了日志记录功能。对名为 log 的未绑定变量的每个方法调用都将映射到对记录器的调用。为此,将在类中插入一个日志字段。如果该字段已存在,则使用此转换将导致编译错误。方法名称将用于确定在记录器上调用什么。

log.name(exp)

映射到

if (log.isNameLoggable() {
        log.name(exp)
     }

这里 name 是信息、调试、警告、错误等的占位符。如果表达式 exp 是常量或仅是变量访问,则不会转换方法调用。但这仍然会导致对注入的记录器的调用。

希望这能澄清发生了什么。我们的日志语句变成了 2 个分支 if,以避免为未启用的日志级别构建昂贵的字符串(据我所知,这是一种常见的做法)。但这意味着为了保证覆盖所有这些分支,我们必须针对每个日志级别重复运行每个测试。

4

1 回答 1

0

我没有找到排除它的通用解决方案,但是如果您的代码库允许您这样做,您可以将您的日志记录语句包装在一个方法中,并在其名称中包含“生成”的注释。

一个简单的例子:

package org.example.logging

import groovy.transform.Generated
import groovy.util.logging.Slf4j

@Slf4j
class Greeter {

    void greet(name) {
        logDebug("called greet for ${name}")
        println "Hello, ${name}!"
    }

    @Generated
    private logDebug(message) {
        log.debug message
    }
}

不幸javax.annotation.Generated的是不合适,因为它只有一个保留SOURCE,因此我(ab)groovy.transform.Generated在这里使用,但可以轻松地为此目的创建自己的注释。

我在这里找到了该解决方案:如何添加注释以从 jacoco 代码覆盖率报告中排除方法?


更新:在 Groovy 中,您可以使用 trait 最优雅地解决它:

package org.example.logging

import groovy.transform.Generated
import groovy.util.logging.Slf4j

@Slf4j
trait LoggingTrait {

    @Generated
    void logDebug(String message) {
        log.debug message
    }
}

...接着...

package org.example.logging

import groovy.util.logging.Slf4j

@Slf4j
class Greeter implements LoggingTrait {

    void greet(name) {
        logDebug "called greet for ${name}"
        println "Hello, ${name}!"
    }

}

不幸的是,该属性log被解释为 的属性Greeter,而不是 的LoggingTrait,因此您必须附加@Slf4j到特征和实现该特征的类。尽管如此,这样做会给您预期的记录器 - 实现类之一:

14:25:09.932 [main] DEBUG org.example.logging.Greeter - called greet for world

于 2021-06-06T11:59:04.123 回答