【问题标题】:Can I automatically execute JUnit testcases once with all logging enabled and once with all logging disabled?我可以在启用所有日志记录和禁用所有日志记录的情况下自动执行 JUnit 测试用例吗?
【发布时间】:2009-06-03 16:18:49
【问题描述】:

我找到了解决方案,请在下面查看我自己的答案。有人有更优雅的吗?

我想这样做是为了增加代码覆盖率并发现细微的错误。

假设要测试以下类:

public class Foo {
    private final Logger logger = LoggerFactory.getLogger(Foo.class);
    public void bar() {
        String param=[..];
        if(logger.isInfoEnabled()) logger.info("A message with parameter {}", param);

        if(logger.isDebugEnabled()) {
            // some complicated preparation for the debug message
            logger.debug([the debug message]);
        }
    }
}

以及以下测试类:

public class FooTest {
    @Test
    public void bar() {
        Foo foo=new Foo();
        foo.bar();
    }
}

一个代码覆盖工具,例如Cobertura 将正确报告仅检查了一些条件分支。

信息和调试为记录器激活或停用。

除了在您的覆盖率上看起来很糟糕之外,这会带来真正的风险。

如果 if(logger.isDebugEnabled()) 里面的代码有一些副作用怎么办?如果您的代码仅在启用 DEBUG 时才有效,并且在日志级别设置为 INFO 时惨遭失败怎么办? (这实际上发生在我们的一个项目中:p)

所以我的结论是,包含记录器语句的代码应始终在启用所有日志记录的情况下测试一次,并在禁用所有日志记录的情况下测试一次......

有没有办法用 JUnit 做类似的事情?我知道如何全局启用或禁用我在 Logback 中的所有日志记录,所以问题是:我怎样才能执行两次测试,一次启用日志记录,一次禁用日志记录。

附言我知道this question,但我不认为这是重复的。我不太关心绝对覆盖率值,而是关心可能包含在 if(logger.isDebugEnabled()) 中的微妙、难以发现的错误。

【问题讨论】:

    标签: java junit code-coverage logback cobertura


    【解决方案1】:

    我已经通过实现一个基类来解决这个问题,如果需要这样的功能,测试类应该扩展它。

    文章Writing a parameterized JUnit test包含解决方案。

    有关日志记录基类,请参阅LoggingTestBase,有关使用它的简单示例,请参阅LoggingTestBaseExampleTest

    每个包含的测试方法都会执行 3 次:

    1. 它像往常一样使用 logback-test.xml 中定义的日志记录来执行。这应该有助于编写/调试测试。

    2. 它在启用所有日志记录并写入文件的情况下执行。该文件在测试后被删除。

    3.它在禁用所有日志记录的情况下执行。

    是的,LoggingTestBase 需要文档;)

    【讨论】:

    • 注意,通过写出应用程序的配置来管理典型应用程序的日志级别并不是一种好的做法。日志框架旨在管理应用程序外部的这种情况。
    • 它们是单元测试,不是应用程序。此外,在某些情况下更改日志级别配置是有意义的,例如控制台应用程序的“-v”命令行选项。
    • 你可以在没有 Joran 的情况下以编程方式配置 logback。你会有更短的代码。此外,如果以编程方式完成配置,您可以在每次测试结束时恢复旧配置。如果您想查看示例代码,请访问 logback-dev。否则,非常好的工作!
    • 谢谢,我会在开发列表中回复您。我不知道 logback 可以通过编程方式配置,除了 Joran,配置可以在重新配置之外恢复。
    【解决方案2】:

    您是否尝试过简单地维护两个单独的日志配置文件?每一个都将在根记录器的不同级别进行记录。

    禁用所有日志记录

    ...
    <root>
        <priority value="OFF"/>
        <appender-ref ref="LOCAL_CONSOLE"/>
    </root>
    ...
    

    启用所有日志记录

    ...
    <root>
        <priority value="ALL"/>
        <appender-ref ref="LOCAL_CONSOLE"/>
    </root>
    ...
    

    执行将通过系统参数在类路径上指定不同的配置:

    -Dlog4j.configuration=path/to/logging-off.xml
    -Dlog4j.configuration=path/to/logging-on.xml
    

    【讨论】:

    • 我在考虑更多关于 Maven 2 和 Logback 的内容。拥有两个配置并初始化日志框架不是问题。事先调用相应的记录器配置方法两次执行测试是我的问题。我认为我应该更清楚地说明这一点。
    • 您可以在 maven 中以可选择的配置文件指定系统参数。您需要两个配置文件,一个带有日志记录,一个没有。让它们都用一个命令执行超出了我的理解
    • @Huxi:请注意,日志配置文件不仅用于初始化日志框架,还用于控制日志级别(这是您正在尝试做的事情)。通过执行两个(或三个)测试运行,您可以完成您想要的,而无需强迫开发人员为此功能创建 3 个单元测试(这就是您所提议的)。您可以使用不同的 Maven 配置文件控制每次运行选择的日志配置。脚本可以负责在一个命令中执行运行。
    • 我希望能够简单地执行“mvn clean install”并执行所有测试。在我自己的答案中使用我的解决方案建议,这是可能的。此外,开发人员只需要像往常一样编写一个普通的测试类。
    【解决方案3】:

    我建议从 JUnit 切换到 TestNG。 TestNG 比 JUnit 有很多高级特性。它使您可以使用不同的配置多次运行测试,我想这就是您所需要的

    【讨论】:

    • JUnit 和 TestNG 可以结合使用吗?我在这里或多或少在谈论 Maven 2 集成……我们所有的测试都是 JUnit 测试……
    • 是的,TestNG 可以运行 JUnit 测试。我一直在 maven2 项目中使用它
    • 将测试从 TestNG 转换为 JUnit 很容易,虽然耗时
    【解决方案4】:

    eqbridges 建议使用不同的日志记录上下文简单地运行两次测试似乎是最简单的。您不必记住在每个有福的测试中编写逻辑代码,这是一个很大的优势。另一个是您可以很容易地看到应该归咎于哪个日志记录级别。

    话虽如此,如果您只需要在一次测试运行中执行此操作,则有几种策略。

    对于 3.8,我会将所有内容都放在套件中,并制作两个套件,每个用于每个日志记录级别,在运行测试之前设置日志记录级别。这在功能上与使用不同的命令行参数运行整个测试套件两次的功能相同,只是您只需运行一次即可。

    在 JUnit 4.x 中,我想到了几个额外的选项:

    一个是自定义跑步者。虽然我无法想出要完成这项工作所需要做的所有事情,但是实际上运行两次测试并使用您的自定义运行程序使用 @RunWith 注释测试的运行程序可以工作。

    另一个是参数化测试。虽然您实际上必须设置每个测试以接受参数(这需要一个接受参数的构造函数),然后根据参数设置日志级别。

    编辑:为响应您对参数化测试的操作方法的请求,here 是运行器上的 javadoc 以帮助您入门,here 是更实用的指南。

    【讨论】:

    • 你有关于参数化测试的文档链接吗? JUnit 常见问题解答最后一次更新是在 2006 年,我找不到类似的东西...... junit.org 上发生了什么?菜谱好像也过时了……
    • 感谢“参数化测试”提示。我找到了一些文档,请参阅我的解决方案。
    【解决方案5】:

    如果您觉得打开所有内容后日志记录过多,也许您可​​以尝试减少日志记录量。如果计算机产生的内容过多,就不是很有用,更不用说人类阅读了。

    【讨论】:

    • 我将所有日志记录路由到一个临时文件中,这样输出就不会被无用的日志消息弄乱。我的问题的重点是我希望能够测试这两种情况:所有日志记录都打开,所有日志记录都关闭。我们确实遇到过这样的情况,即如果在启用调试的情况下运行一个类,而只启用信息则不会。我想以一般的方式捕捉这些问题。
    猜你喜欢
    • 2016-12-17
    • 1970-01-01
    • 2018-03-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-01-23
    • 1970-01-01
    相关资源
    最近更新 更多