单元测试:记录和依赖注入(Unit Testing: Logging and Dependency

2019-07-30 16:10发布

因此,对于从互联网上最好的回应似乎是SO和其他站点的日志记录:

void DoSomething() {
    Logger.Log("Doing something!");
    // Code...
}

现在一般你避免静电的方法,但在日志记录的情况下(特殊情况),这是最简单和cleaniest路线。 在静态类,你可以很容易地通过一个配置文件/框架注入一个实例来给你DI同样的效果。

我的问题来自于一个单元测试的角度来看。

在该示例代码上述想象的DoSomething的点()是两个数字加在一起。 我会写我的单元测试这样的好。 什么记录?

我会写的日志记录单元测试(尚未使用mock实例记录器本身)? 我知道,如果是这样的话我会写一个集成测试,以证明该记录器实际上是写一个日志文件,但我不知道。

下面的测试驱动开发(我也)单元测试将需要我决定了接口没有?

有什么建议?

Answer 1:

就个人而言,我实践TDD / BDD漂亮的宗教,我几乎从来没有测试记录。 但有一些例外记录或者是一个开发者方便或可用性的因素,而不是方法的核心规范的一部分。 它也往往有变化比方法的实际语义的比例高出许多,所以你风,只是因为你增加了一些更多的信息记录,开断试验。

这可能是值得的有一些测试,简单地行使记录子系统,但对于大多数应用程序,我不会测试每个类使用日志中的一种特殊的方式。



Answer 2:

我只写过日志记录了几个单元测试。 这是一个痛苦,要么使得生产代码凌乱(由于注入记录器)或臭试验(用mock替换静态记录器)。 不像McWafflestix,我经常不认为它是值得的努力之后。

多少钱你真的想知道日志是否工作,超出了你会通过其他(动手)测试看到了什么? 您可能需要使用DI偶尔类,其中记录是非常重要的,但除此之外,我不会理会测试记录。

这是假设日志是一个调试性质的-如果它是一个审计日志或类似的东西(的东西有功能性要求),这是一个不同的问题。



Answer 3:

我会分裂日志分为三类:

1)的要求。 某些系统需要记录的审计目的,或填补项目的一些其他要求(如应用程序服务器的日志记录标准)。 然后,它的确是一个必要条件,值得单元测试和验收测试的地步,你可以放心的要求得到满足。 因此,在这种情况下,日志的确切字符串可用于测试。

2)问题的解决。 如果你开始QA或生产越来越怪异状态,你希望能够追踪到底是怎么回事。 一般情况下,我会说,如果这是重要的(说,在高度线程化应用程序,其中状态可能很复杂,但无法通过已知的步骤进行复制),然后测试在给定状态值,最终记录的是有价值的(所以你AREN “T测试日志的可读性整体,只是某些事实在那里得到的)。 即使类稍后改变,该状态仍可能会记录(用另外的状态一起),以便测试和记录之间的耦合是合理的。 因此,在这种情况下,仅记录的部分被用于测试(一个包含检验)。

3)发展援助。 在许多情况下,我使用日志记录作为评论的一个更强大的形式。 你可以写这样的声明:

 logger.debug("Extract the fifth instance of BLAH from the string " + s);

所以,你可以记录代码,并在同一时间有一个有用的神器,如果你以往任何时候都需要调试是怎么回事。 在这种情况下,我不会单元测试所有的,因为存在与否给定的说法是不是对自己很重要的。

至于你要测试所有的100%的观点,看到Kent Beck的答案在这里 。 我认为,“测试一切”,是初学者很好的建议,因为当你开始使用TDD的诱惑将是无法测试任何东西,是很难进行测试,或者是推动你去思考设计,使其可测试的,并理顺它是不重要的。 但是,一旦你知道你在做什么,并欣赏测试的价值,那么它来平衡你用什么值得测试做什么是非常重要的。



Answer 4:

大多数日志框架允许您为组件提供自定义实现。 您可以使用该配置机制来提供自己的实现。


例如,Java的Log4J的允许你声明定制的appender ,这是负责“提供”一个LoggingEvent所的组件。

记录器可以很容易地嘲笑和使用注射:

Appender appenderMock = EasyMock.createMock(Appender.class);
/* expect */ appenderMock.doAppend(EasyMock.isA(LoggingEvent.class));
EasyMock.replay(appenderMock);

Logger.getLogger(/* replace with your own */"My logger").addAppender(appenderMock);

EasyMock.verify(appenderMock);

这个测试只验证日志事件被发送,但可以使用完善它更EasyMock的 。



Answer 5:

我说这可能是写单元测试的记录一件合理的事; 我这样做之前,它原来是比我最初的预期更加有用。 一般来说,单元测试记录为您提供了良好的保证,日志工具在单元测试时间的工作,它可以是一个很好的保证。 我并不觉得单元测试记录的关键,但如果你有倾斜度,我怀疑这将是一件坏事,无论是。



Answer 6:

我个人认为它的矫枉过正的单元测试记录的声明。 但如果你真的想这样做,那么模拟记录器会工作,或者,如果使用类似log4j的框架,附加目的地是在试运行期间使用编写自定义。



Answer 7:

我通常做的断言上有什么不记录的单元测试记录语句,但我检查我的单元测试所采取的代码路径覆盖记录语句只是为了确保在登录例外,我没有得到一个例外!



Answer 8:

我可能会有的单元测试的记录器本身的独立机构,从一切单独测试它的各种功能。 在正在使用的记录器的方法,我只想测试记录器被调用(即期望它被称为)用正确的参数。 举例来说,如果我有一个方法:

DoSomething()
{
    if (FatalErrorOccurred)
    {
        Logger.Log("Fatal Error", ErrorLevel.Fatal);
    }
}

我会写一个测试,显示记录器记录的一个致命错误消息时FatalErrorOccurred是真实的。 我不会,当然,测试错误信息本身的内容,因为这是很容易改变。



Answer 9:

虽然我与他人,我不会申请拓展署伐木同意,我会尽量保证单元测试覆盖了包含日志语句的所有代码路径。 而且重要的是确保在运行单元测试,让所有的日志语句执行的最高详细级别配置。

例如,下面的代码具有将抛出只有当调试级别启用跟踪一个出现FormatException错误。

if (logger.IsDebugEnabled)
{
    string message = String.Format(CultureInfo.CurrentCulture, 
          "... {1} ...", someValue);
    logger.Debug(message);
}


文章来源: Unit Testing: Logging and Dependency Injection