在单元测试中是否有任何slf4j用法的简单模式?

问题描述:

我在我的项目中使用JUnit4和Hibernate3。 Hibernate依赖于Slf4j,因此我的项目也包含这个库。现在我想在单元测试中使用Slf4j以记录补充测试信息。您能否提供一个简单的示例,说明我的单元测试应该如何才能记录一行文本?在多次测试中,最好是没有代码重复在单元测试中是否有任何slf4j用法的简单模式?

我也喜欢用SLF4J在我的JUnit测试我DAO类。它在您创建新测试或修改旧测试时确实有帮助。我通常会将我的旧日志记录输出保留在调试级别,并在信息级别创建新的日志记录语句,同时我仍在积极研究该方法中的代码。我的一个JUnit类的会是这个样子:

package com.example.mydao; 

import org.slf4j.Logger; 
import org.slf4j.LoggerFactory; 
// other imports not shown... 

public class TestMyDAO extends TestCase { 

    private static final Logger logger = 
     LoggerFactory.getLogger(TestMyDAO.class); 


    public void testA() { 
     logger.debug("Logging from testA() method"); 
    } 

    public void testB() { 
     logger.debug("Logging from testB() method"); 
    } 

    public void testThatIAmWorkingOn() { 
     logger.info("Logging from my new test method at INFO level"); 
    } 

} 

我使用log4j的是实际的记录供应商,所以我log4j.xml配置文件看起来像这样:

<?xml version="1.0" encoding="UTF-8"?> 
    <!DOCTYPE log4j:configuration SYSTEM "log4j.dtd"> 
    <log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/" debug="false"> 
    <appender name="consoleAppender" class="org.apache.log4j.ConsoleAppender"> 
     <layout class="org.apache.log4j.PatternLayout"> 
      <param name="ConversionPattern" value="%d %-5p [%c{1}] %m %n" /> 
     </layout> 
    </appender> 

    <logger name="com.example.mydao" additivity="false"> 
     <level value="INFO" /> 
     <appender-ref ref="consoleAppender"/> 
    </logger> 

    <logger name="org.hibernate" additivity="false"> 
     <level value="WARN" /> 
     <appender-ref ref="consoleAppender"/> 
    </logger> 

    <logger name="org.hibernate.connection.DriverManagerConnectionProvider" additivity="false"> 
     <level value="INFO" /> 
     <appender-ref ref="consoleAppender"/> 
    </logger> 

    <logger name="org.hibernate.connection.C3P0ConnectionProvider" additivity="false"> 
     <level value="INFO" /> 
     <appender-ref ref="consoleAppender"/> 
    </logger> 

    <logger name="com.mchange" additivity="false"> 
     <level value="WARN" /> 
     <appender-ref ref="consoleAppender"/> 
    </logger> 

    <logger name="com.mchange.v2.resourcepool.BasicResourcePool" additivity="false"> 
     <level value="INFO" /> 
     <appender-ref ref="consoleAppender"/> 
    </logger> 

    <logger name="com.mchange.v2.c3p0.impl.AbstractPoolBackedDataSource" additivity="false"> 
     <level value="INFO" /> 
     <appender-ref ref="consoleAppender"/> 
    </logger> 

    <logger name="com.mchange.v2.c3p0.C3P0Registry" additivity="false"> 
     <level value="INFO" /> 
     <appender-ref ref="consoleAppender"/> 
    </logger> 

    <root> 
     <priority value ="WARN" /> 
     <appender-ref ref="consoleAppender"/> 
    </root> 

</log4j:configuration> 

这给了我的信息从我的JUnit类输出,以及Hibernate运行时和Hibernate使用的其他库中的一些有用的东西。根据自己的口味调整。

最后,我需要确保所有的下列库都在我的类路径中,当我执行JUnit测试:

  • slf4j-api-1.6.0.jar
  • slf4j-log4j12-1.6.0.jar
  • log4j-1.2.16.jar
  • log4j.xml(我的配置文件,如上所示)
  • 某些版本的JUnit运行时JAR
  • 在生产中运行应用程序时,通常存在的所有JAR

这就是我在使用log4j时所做的。如果您使用不同的日志记录实施,则相应地进行调整。只要“API”和实现JAR是相同版本(我的版本都是1.6.0),使用不同版本的slf4j并不重要。

+0

为避免代码重复,您可以将导入和“Logger”声明移至抽象的“TestCase”子类。 – 2012-11-12 21:34:46

为什么你想在单元测试中记录东西?单元测试应该是合格/不合格,并且应该使用测试框架来表明这一点。您不想通过输出来阅读测试是否通过或失败。如果它失败了,那么在IDE /调试器中运行它是修复它的最好方法。

+11

因为它有时可以用来了解测试失败的原因,或者打印性能指标,以防您随意关注这些测试。 – BjornS 2010-09-29 11:43:50

+6

如果您想进行性能测试,请正确执行并捕获并绘制数字。随便看看UT跑步中的一些数字并不是衡量表现的方法。至于为什么一个测试失败,你应该写你的断言,所以文本告诉你出了什么问题。在工作中,我们的产品有数万个单元测试;如果我们必须阅读那些输出结果,你认为我们会在哪里? – dty 2010-09-29 11:47:13

+2

我没有说性能测试,我只是说随便跟踪它作为你为什么要登录你的测试的例子。至于你的工作,是的,我们也有数以万计的测试,你会惊讶地发现你想要的信息与特定测试有关。此外,除非你真的需要,而且当你真的需要的时候,你不需要阅读它们,它的方便已经有日志了。 – BjornS 2010-09-29 11:52:52

这对我来说似乎是一种难闻的气味。

您应该始终避免手动检查或单元测试验证。

单元测试应该是自动化的,如果你的构建工具告诉你,某些测试失败应该只需要人工干预,并应使用所有这些验证方法(如的assertEquals)

+2

当然可以。 OP想知道代码*应该看起来像做什么,我们中的许多人都建议不要存在代码。这就是它*应该如何。 – iX3 2015-02-03 14:45:16

+0

有趣的是,dyt的另一个答案基本上是说类似的东西(人们应该避免因为blablabla而在单元测试中登录)。我的回答是收到更多的赞誉。 LOL – 2015-11-24 07:00:51

+0

在测试期间记录通常是非常宝贵的,特别是当测试失败时。当测试通过或日志变得不可读时,这当然需要与过多的日志记录进行平衡。 – AntonPiatek 2017-12-14 15:51:40

我们使用log4j的提供失败的原因作为我们的输出记录器;

private static Logger log = LoggerFactory.getLogger(MyClassHere.class); 

如果您正确配置它,slf4j应找到并使用log4j而不会出现问题。 为了让生活方便,我会用这个Eclipse的模式,因为您将编写这些代码公平一点:

private static Logger log = LoggerFactory.getLogger(${enclosing_type}.class); 
${:import(org.slf4j.Logger,org.slf4j.LoggerFactory)} 

的测试中,我建议你不要超越INFO水平,并保持最事情DEBUG 。如果你真的想要智能地捕捉很多错误,那么我建议你查看一下PositronLogger,它是一个日志文件appender,它会静静地将所有东西都提取到TRACE中,但只有在捕获错误时才将其转储到文件;有点像时间旅行:)

http://github.com/andreaja/PositronLogger

+0

我需要在'@ Before'注释的方法内的每个单元测试中执行'getLogger()',对吧? – yegor256 2010-09-29 14:12:49

+0

不,只是私有静态引用,那么你可以简单地调用log.debug(“some stuff”);无论你喜欢哪里。编辑:我应该澄清; LoggerFactory.getLogger()是静态引用的一部分,您不需要在@Before中调用它,只需将其作为测试类中的字段输入即可。一个简单的例子:class MyTests {private static Logger log = LoggerFactory.getLogger(MyTests.class); @Test public void magic(){log.info(“...”); }} – BjornS 2010-10-01 08:26:45

Slf4j是一个日志门面,您可以在运行时决定实现。 Slf4j只是一个API。例如,你可以使用log4j作为底层实现。你需要在你的pom.xml中包含两个依赖。

<!-- Depend on slf4j API --> 
    <dependency> 
     <groupId>org.slf4j</groupId> 
     <artifactId>slf4j-api</artifactId> 
     <version>1.7.12</version> 
    </dependency> 
    <!-- Use log4j as the slf4j implementation --> 
    <dependency> 
     <groupId>org.slf4j</groupId> 
     <artifactId>slf4j-log4j12</artifactId> 
     <version>1.7.12</version> 
    </dependency> 

的事情是,运行在IDE或通过mvn test单元测试时,它可以是恼人设置log4j的配置。尤其是以一种不需要做任何事情的方式工作。除非在类路径上有一个log4j.properties文件或者设置了-Dlog4j.configuration=file:///path/to/log4j.properties,否则Log4j默认拒绝记录任何内容。

一种解决方案是把在单元测试,代码设置log4j的配置编程:

@BeforeClass 
    public static void beforeClass() { 
     BasicConfigurator.resetConfiguration(); 
     BasicConfigurator.configure(); 
    } 

这只是工作,但它需要在单元测试这是一种痛苦被投入。 。

另一种解决方案是将日志记录实现切换为仅用于测试的简单实现。

所以在你的pom.xml

<!-- Depend on slf4j API --> 
    <dependency> 
     <groupId>org.slf4j</groupId> 
     <artifactId>slf4j-api</artifactId> 
     <version>1.7.12</version> 
    </dependency> 

    <!-- Use SimpleLogger as the slf4j implementation in test --> 
    <dependency> 
     <groupId>org.slf4j</groupId> 
     <artifactId>slf4j-simple</artifactId> 
     <version>1.7.12</version> 
     <scope>test</scope> 
    </dependency> 

    <!-- Use log4j as the slf4j implementation during runtime (not test) --> 
    <dependency> 
     <groupId>org.slf4j</groupId> 
     <artifactId>slf4j-log4j12</artifactId> 
     <version>1.7.12</version> 
     <scope>runtime</scope> 
    </dependency> 

的SimpleLogger只是默认记录一切标准错误,并且不需要任何配置文件

+1

SimpleLogger默认日志级别是INFO。例如,要将其更改为DEBUG,请使用JVM选项 -Dorg.slf4j.simpleLogger.defaultLogLevel = DEBUG – 2017-10-25 15:31:54

添加日志记录在写新的测试是非常有用的。与此同时,当测试在CI或CD管道中运行时,您希望禁用日志记录(或者至少不要冗长)。有时候故障是暂时的,特别是在端到端的运行中,所以在CI作业的控制台日志上输出相关的输出是有帮助的。这篇文章很好地描述了它 - https://gualtierotesta.wordpress.com/2015/11/01/tutorial-logging-during-tests/