我们应该单元测试日志记录吗?

2022-09-01 06:13:44

通常在代码中看到日志记录功能:

public class A {

    private static final Log LOG = LogFactory.getLog(A.class);

和用法:

} catch (Exception e) {
    LOG.error(e.getMessage(), e);
    throw e;
}

但我从未见过这种代码的单个单元测试。

当然,我会测试抛出异常和异常类型,但是我应该编写测试来检查日志记录信息吗?我倾向于认为日志记录是系统行为的另一部分,因此在测试中涵盖它从逻辑上讲是退出的。

假设我应该覆盖它,意味着我应该更改我的原始代码以注入模拟日志,并检查“error”方法是否被预期的消息调用。但是,如果我的原始类是服务,并且它在spring上实例化,我是否应该注入一些记录器以及其他依赖项?


答案 1

测试日志记录库不是由您决定的。但是,值得测试的是,当引发异常时,您的类会在正确的级别记录一条消息。您正在测试的是,您的代码对日志记录库执行了正确的操作。

若要使上述代码可测试,请使用依赖关系注入。这假定记录器实现了一个接口 。您可以将记录器作为构造函数参数传递给类 A。然后,测试代码将创建 一个 模拟实现,并将其传递到构造函数中。上面的代码中没有显示异常是如何产生的,但大概是通过其他一些依赖对象。所以你也嘲笑它,并让它抛出一个异常。然后检查模拟是否调用了该方法。也许你想检查它记录的消息,但这可能太过分了,使测试代码脆弱。ILogILogILogerror


答案 2

是的,当日志记录正在执行所需的操作时,我们应该测试日志记录。例如,在某些外部应用程序中有钩子,用于扫描日志中的某些事件。在这种情况下,您当然希望确保完成日志记录。

当然,您不想测试每个日志记录事件,我认为应该只测试ERRER(而不是全部)。

使用现代日志记录框架(如 SLF4j),您只需注入一个自定义处理程序,该处理程序将 的事件存储在内存中,并且可以在以后断言。

现在我想到的有两个:

SLF4J测试:不需要修改日志记录配置,但需要注入日志记录工厂,这可能会导致代码被修改。

SLF4J测试:不像slf4jtesting那么强大,似乎没有被开发,但与现有代码配合得很好。除了用于测试的记录器配置外,无需进行任何修改。

使用SLF4J测试时,断言非常严格,并检查整个事件的相等性。在这种情况下,自定义匹配器可能很有趣:

public static Matcher<LoggingEvent> errorMessageContains(final String s) {
    return new TypeSafeMatcher<LoggingEvent>() {
        @Override
        public void describeTo(final Description description) {
            description.appendText(" type " + Level.ERROR + " should contain ")
                    .appendValue(s);
        }

        @Override
        protected void describeMismatchSafely(final LoggingEvent item, final Description mismatchDescription) {
            mismatchDescription.appendText(" was type ").appendValue(l)
                    .appendText(" message ").appendValue(item.getMessage());
        }

        @Override
        protected boolean matchesSafely(final LoggingEvent item) {
            return item.getLevel().equals(Level.ERROR)
                    && item.getMessage().contains(s);
        }
    };
}

这仅检查消息是否包含文本,但如果它相等,则不检查。因此,当修改消息以修复拼写错误或提供更多详细信息时,如果仍然包含基本部分,则测试不会中断。


推荐