使用JMockit模拟和验证SLF4J

mer*_*oth 4 java junit unit-testing jmockit slf4j

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

 public class MyClass {

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

    public void foo() {
      log.warn("My warn");
    }
  }
Run Code Online (Sandbox Code Playgroud)

我需要用JMockit测试它,如:

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

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

顺便说一下,我正在使用JMockit(1.29)的最新版本,你不能再为最终静态字段设置setField(log).

Thu*_*rge 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(); 
 }
Run Code Online (Sandbox Code Playgroud)

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

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

另外,您也可以使用@Mocked上都LoggerLoggerFactory

在某些情况下,@Capturing由于注释工作原理的复杂性,将无法按预期工作.幸运的是,你还可以通过使用获得同样的效果@Mocked上都LoggerLoggerFactory像这样:

 @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);
   }};
 }
Run Code Online (Sandbox Code Playgroud)

注意: JMockit 1.34到1.38 有一个错误,可以防止它与slf4j-log4j12SLF4J 一起使用,也可能是其他依赖项.如果遇到此错误,请升级到1.39或更高版本.