如何验证(使用单元测试)错误堆栈已打印在日志文件中? [英] How to verify (with unit test) that error stack is printed in the log file?

查看:203
本文介绍了如何验证(使用单元测试)错误堆栈已打印在日志文件中?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在继续此答案中,我编写了一个单元测试以验证如果出错,将打印堆栈在日志文件中.

In continuing to this answer I wrote a unit test to verify that in case of error, the stack will be printed in the log file.

经过测试的方法

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

private final Logger logger = LoggerFactory.getLogger(getClass());

public long getFq(String fi) {
    try {            
        return calcSomeThing(fi.toLowerCase());
    } catch (Exception e) {
        logger.error("unable to calculate SomeThing.  Error: "
                , e);
        return -1;
    }
}

单元测试:

import ch.qos.logback.classic.Level;
import ch.qos.logback.classic.Logger;
import ch.qos.logback.classic.spi.ILoggingEvent;
import ch.qos.logback.core.read.ListAppender;
import org.slf4j.LoggerFactory;

@Test
public void getFileQualifier() {

    // get Logback Logger
    Logger logger = (Logger) LoggerFactory.getLogger(QService.class);

    // create and start a ListAppender
    ListAppender<ILoggingEvent> listAppender = new ListAppender<>();
    listAppender.start();

    // add the appender to the logger
    // addAppender is outdated now
    logger.addAppender(listAppender);

    // call method under test
    QService.getFq(null);

    // JUnit assertions
    List<ILoggingEvent> logsList = listAppender.list;
    Assert.assertEquals("unable to calculate SomeThing.  Error: ", logsList.get(0)
            .getFormattedMessage());
    Assert.assertEquals(Level.ERROR, logsList.get(0)
            .getLevel());

    Assert.assertEquals("java.lang.NullPointerException: null", logsList.get(1)
            .getMessage());
    Assert.assertEquals(Level.ERROR, logsList.get(1)
            .getLevel());

    Assert.assertThat("(QService.java", containsString(logsList.get(2)
            .getMessage()));
    Assert.assertEquals(Level.ERROR, logsList.get(2)
            .getLevel());
}

好吧,尽管我可以看到堆栈确实打印在日志文件中,但是由于 logsList仅包含一项(第一条打印行 [无法计算Something.错误:]).

Well, although I can see the stack is indeed printed in the log file, the unit test failed because of the logsList contains only one item (the first printed line only [unable to calculate SomeThing. Error: ]).

java.lang.IndexOutOfBoundsException:索引1超出长度1的范围

java.lang.IndexOutOfBoundsException: Index 1 out of bounds for length 1

为什么会发生这种情况以及如何对其进行测试?

Why does it happen and how it can be tested?

编辑

答案: 答案(所有内容均来自 @Gavin 的答案和评论,谢谢):

Answers: the answers (all are quotes from @Gavin's answer and comment, thank you):

关于第一个问题(为什么会发生),答案是:

On the first question (Why does it happen) the answer is:

在我看来,异常与日志事件中的消息分开存储

It looks to me that exceptions is stored separately from the message in the log event

关于第二个问题(如何进行测试),答案是:

On the second question (how it can be tested) the answer is:

在日志事件列表中查找要查找的内容,并可以用适合您的域的方式表示,例如,检查Throwable是否已记录,也许在org.apache.log4j.spi.LoggingEvent中查找适当的方法

to find what you are looking for in the list of log events and can be expressed in a manner suitable to your domain, e.g checking the that a Throwable was logged, perhaps looking in org.apache.log4j.spi.LoggingEvent for appropriate methods

最后,我要验证的代码是:

Finally, my code to verify it was:

Assert.assertEquals(logsList.get(0).getThrowableProxy().getClassName(), "java.lang.NullPointerException");

推荐答案

这是我过去捕获日志消息的方式,它基于一个似乎不再可用的旧博客(不是我写的).

This is how I have captured log messages in the past, this is based on an old blog (not written by me) that no longer seems to be available.

这是为Java 7/8和Junit4编写的相当古老的代码.

It is quite old code written for Java 7/8 and Junit4.

我会尽量保持简短:)

首先,您需要一个Appender,最好是扩展AppenderSkeleton,例如:

First you need an Appender it is probably best to extend the AppenderSkeleton, something like:

public class RuleAppender extends AppenderSkeleton {
    private final List<LoggingEvent> loggingEvents = new ArrayList<>();

    protected RuleAppender() {
        super(true);

        this.setThreshold(Level.TRACE);
        setName("Rule Appender");
    }

    @Override
    public void close() {
        // No op in this case
    }

    @Override
    public boolean requiresLayout() {
        return false;
    }

    @Override
    protected void append(final LoggingEvent event) {
        loggingEvents.add(event);
    }

    public boolean hasEventsMeeting(LogExpectation logExpectation) {
         // Use the LogExpectation to determine if the list of log events contains what you want.
    }

    @Override
    public String toString() {
        return "RuleAppender";
    }
}

LogExpectation只是在某个地方也定义了期望/条件以与存储的日志事件相匹配.

The LogExpectation is simply somewhere too define an expectation/criteria to match against the stored log events.

然后将其包裹在Junit规则中,以使将Appender添加到Log4J变得更加容易,我通过实现TestRule并扩展Statement来做到这一点,确保第一件事Statement s evaluate方法是:

This is then wrapped up in a Junit Rule to make adding the the Appender to the Log4J a little easier, I did this by implementing TestRule and extending Statement, ensuring the first thing Statements evaluate method does is:

LogManager.getRootLogger().addAppender(ruleAppender);
LogManager.getRootLogger().setLevel(Level.ALL);

注释: 只要在测试之前执行了以上两行,以确保将追加添加到Log4J(仍然需要自定义追加器),就可以在没有JUnit规则的情况下完成此操作.

Notes: This can be done without a JUnit rule, so long as the above two lines are executed before the test in order to ensure the appending is added to Log4J (The custom appender is still required).

我还没有进入JUnit规则代码,因为我们可能应该转向不支持Rules的JUnit 5,并且我也没有进入LogExpecation,因为这很容易在列表中找到您要查找的内容日志事件,可以用适合您的域的方式表示,例如检查Throwable是否已记录,也许在org.apache.log4j.spi.LoggingEvent中寻找适当的方法

I have not gone into the JUnit rule code, as we probably should be moving to JUnit 5 which doesnt support Rules and I have not gone into LogExpecation as this is simply away to find what you are looking for in the list of log events and can be expressed in a manner suitable to your domain, e.g checking the that a Throwable was logged, perhaps looking in org.apache.log4j.spi.LoggingEvent for appropriate methods

这篇关于如何验证(使用单元测试)错误堆栈已打印在日志文件中?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆