java - 使用 Mockito/PowerMock 验证日志是否已写入

标签 java logging junit mockito powermock

我有一个将消息写入某些日志的类。该类是一个不执行任何其他操作的实用程序,它在后台运行,检查一些内容并记录它们。我想知道我是否有可能在单元测试中验证日志是否已被写入而不关心它实际写的是什么。这是我正在测试的类(class):

//imports...

public class MyClass {
  private static Log log = LogFactory.getLog(MyClass.class);

  public MyClass() {
    log.info("MyClass is being created.");
  }

  public void doThing() {
    if( everything_is_fine ) {
      log.info("This is a message to say everything is fine.");
    } else {
      log.error("Uh oh...");
    }
  }
}

还有我的测试类:

// imports ...

@RunWith(PowerMockRunner.class)
@PrepareForTest({MyClass.class,LogFactory.class})
public class MyClassTest {
  Log mockLog;

  @Before
  public void setup() {
    PowerMockito.mockStatic(LogFactory.class);
    mockLog = mock(Log.class);
    PowerMockito.when(LogFactory.getLog(MyClass.class)).thenReturn(mockLog);
  }

  @Test
  public void test_everything_is_ok() {
    MyClass mything = new MyClass();    // should write to log.info
    mything.doThing();                  // should write to log.info

    verify(mockLog, atLeastOnce()).info(anyString());
    verify(mockLog, never()).error(anyString());
  }

  @Test
  public void test_everything_is_not_ok() {
    MyClass mything = new MyClass();    // should write to log.info

    // do something which makes things not ok

    mything.doThing();                  // should write to log.error

    verify(mockLog, atLeastOnce()).info(anyString());
    verify(mockLog, atLeastOnce()).error(anyString());
  }
}

当我运行测试时,我希望两个测试都调用 log.info(),而第二个测试只调用 log.error()。但是,我得到了两个测试的 log.info 的“需要但未调用”。第二个是 log.error。所以要么:
1) 我的代码坏了,没有写入日志,或者
2) 我的测试失败了。

我在想我在测试中搞砸了一些东西,可能是一些非常明显的东西,所以有没有人有测试过这样的东西的经验可以帮助我?我们将不胜感激。

更新:

感谢那些提供帮助的人,我现在有了解决方案。

在对代码进行了一番研究之后,我发现日志的初始化似乎存在问题。执行 private static Log log = LogFactory.getLog(MyClass.class); 似乎没有正确使用模拟,所以如果我将它移动到构造函数,它似乎被模拟了 OK 并且我的测试全部按预期工作:

public class MyClass {
  private static Log log;

  public MyClass() {
    MyClass.log = LogFactory.getLog(MyClass.class);
    log.info("MyClass is being created.");
  }

  // etc ...
}

我现在已经可以使用了,但是谁能解释为什么第一种方式初始化日志不起作用?或者也许指向我解释它的地方?我不确定我对 Java 如何初始化对象的理解是否存在差距,或者这是否是模拟框架的限制。

最佳答案

您可以像我们在项目中所做的那样对 Logger 进行抽象:

https://github.com/4finance/uptodate-gradle-plugin/blob/master/src/main/groovy/com/ofg/uptodate/LoggerProxy.groovy

然后你必须构造函数

https://github.com/4finance/uptodate-gradle-plugin/blob/master/src/main/groovy/com/ofg/uptodate/UptodatePlugin.groovy

一个初始化了 LoggerProxy,一个用于测试,您可以模拟它并验证是否传递了正确的文本。不需要肮脏的黑客 ;)

关于java - 使用 Mockito/PowerMock 验证日志是否已写入,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17566114/

相关文章:

java - mockito test 在作为 junit test 运行时没有给出这样的方法错误,但是当在运行配置中手动添加 jar 时,它运行良好

javascript - 从长字符串中提取两项的正则表达式

java - websphere 中的自动 Jenkins 部署

java - 混合 log4j 1.x 和 log4j 2

java - 使用 JUnit 和 Selenium WebDriver 时浏览器未启动

junit - 在 JUnit 中将 "assertTrue"重写为 "assertThat"?

java - 如何将数组转换为不带逗号/括号的字符串格式并添加括号作为值

java - 使用 XML 文件读取和渲染演示文稿的最佳方式

java - 如何使用 Spring MVC 正确记录 http 请求

ios - Objective c 自定义对象描述问题