使用JMockit模拟和验证SLF4J

时间:2016-11-17 16:46:43

标签: java unit-testing junit slf4j jmockit

我有一个SLF4J记录器实例的类,如:

 public class MyClass {

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

    public void foo() {
      log.warn("My warn");
    }
  }

我需要用JMockit测试它,如:

 @Test
 public void shouldLogWarn(@Mocked Logger log) throws Exception {
   new Expectations() {{
     log.warn(anyString);
   }};
   MyClass my = new MyClass();
   my.foo(); 
 }

经过大量搜索后我发现,我需要以某种方式使用MockUp。但无法准确地了解它。

顺便说一句,我使用的是最后一个版本的JMockit(1.29),你不能再 setField(log)来获得最终的静态字段。

1 个答案:

答案 0 :(得分:6)

JMockit具有适用于此情况的@Capturing注释

  

表示模拟字段或模拟参数,扩展/实现模拟类型的所有类也将被模拟。

     

捕获模拟类型的未来实例(即,在测试期间稍后创建的实例)将与模拟字段/参数相关联。在模拟字段/参数上记录或验证期望时,这些关联的实例被视为等效于为模拟字段/参数创建的原始模拟实例。

这意味着如果您使用@Capturing而不是@Mocked对其进行注释,则在测试运行期间创建的每个Logger都将与您注释的相关联。以下是有效的:

 @Test
 public void shouldLogWarn(@Capturing final Logger logger) throws Exception {
   // This really ought to be a Verifications block instead
   new Expectations() {{
     logger.warn(anyString);
   }};
   MyClass my = new MyClass();
   my.foo(); 
 }

作为旁注,如果您要做的只是验证方法是否被调用,那么最好使用Verifications,因为这是它的目的。所以你的代码看起来像这样:

 @Test
 public void shouldLogWarn(@Capturing final Logger logger) throws Exception {
   MyClass my = new MyClass();
   my.foo(); 
   new Verifications() {{
     logger.warn(anyString);
   }};
 }

或者,您可以在@MockedLogger

上使用LoggerFactory

在某些情况下,由于注释工作原理的复杂性,@Capturing无法按预期工作。幸运的是,您可以使用@MockedLogger LoggerFactory来获得相同的效果,如下所示:

 @Test
 public void shouldLogWarn(@Mocked final LoggerFactory loggerFactory, @Mocked final Logger logger) throws Exception {
   MyClass my = new MyClass();
   my.foo(); 
   new Verifications() {{
     logger.warn(anyString);
   }};
 }

注意: JMockit 1.34到1.38 has a bug会阻止它使用slf4j-log4j12,以及可能还有SLF4J的其他依赖项。如果您遇到此错误,请升级到1.39或更高版本。