使用 JMockit 模拟和验证 SLF4J

Mocking and verifying SLF4J with JMockit

我有一个 class,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)

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

Indicates a mock field or a mock parameter for which all classes extending/implementing the mocked type will also get mocked.

Future instances of a capturing mocked type (ie, instances created sometime later during the test) will become associated with the mock field/parameter. When recording or verifying expectations on the mock field/parameter, these associated instances are regarded as equivalent to the original mocked instance created for the mock field/parameter.

这意味着如果您使用 @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);
   }};
 }

或者,您可以在 LoggerLoggerFactory

上使用 @Mocked

在某些情况下,@Capturing 由于注释工作方式的复杂性,无法按预期工作。幸运的是,您也可以通过在 LoggerLoggerFactory 上使用 @Mocked 来获得相同的效果,如下所示:

 @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 或更高版本。