当前位置: 首页 > 面试题库 >

使用PowerMock和Mockito模拟Logger和LoggerFactory

樊胜
2023-03-14
问题内容

我有以下要模拟的Logger,但要验证是否正在调用日志条目,而不是内容。

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

我想模拟用于LoggerFactory.getLogger()的任何类,但是我找不到如何做到这一点。到目前为止,这是我最终得到的结果:

@Before
public void performBeforeEachTest() {
    PowerMockito.mockStatic(LoggerFactory.class);
    when(LoggerFactory.getLogger(GoodbyeController.class)).
        thenReturn(loggerMock);

    when(loggerMock.isDebugEnabled()).thenReturn(true);
    doNothing().when(loggerMock).error(any(String.class));

    ...
}

我想知道:

  1. 我可以模拟静态模型LoggerFactory.getLogger()以用于任何课程吗?
  2. 我只能似乎运行when(loggerMock.isDebugEnabled()).thenReturn(true);@Before,因此我似乎无法改变每个方法的特点。有没有解决的办法?

编辑结果:

我以为我已经尝试过了,但没有成功:

 when(LoggerFactory.getLogger(any(Class.class))).thenReturn(loggerMock);

但是,谢谢,因为它确实起作用了。

但是,我尝试了无数种变化来:

when(loggerMock.isDebugEnabled()).thenReturn(true);

我无法使loggerMock改变其行为,@Before但这仅在Coburtura中发生。使用三叶草,覆盖率显示为100%,但无论哪种方式仍然存在问题。

我有这个简单的课程:

public ExampleService{
    private static final Logger logger =
            LoggerFactory.getLogger(ExampleService.class);

    public String getMessage() {        
    if(logger.isDebugEnabled()){
        logger.debug("isDebugEnabled");
        logger.debug("isDebugEnabled");
    }
    return "Hello world!";
    }
    ...
}

然后我有这个测试:

@RunWith(PowerMockRunner.class)
@PrepareForTest({LoggerFactory.class})
public class ExampleServiceTests {

    @Mock
    private Logger loggerMock;
    private ExampleServiceservice = new ExampleService();

    @Before
    public void performBeforeEachTest() {
        PowerMockito.mockStatic(LoggerFactory.class);
        when(LoggerFactory.getLogger(any(Class.class))).
            thenReturn(loggerMock);

        //PowerMockito.verifyStatic(); // fails
    }

    @Test
    public void testIsDebugEnabled_True() throws Exception {
        when(loggerMock.isDebugEnabled()).thenReturn(true);
        doNothing().when(loggerMock).debug(any(String.class));

        assertThat(service.getMessage(), is("Hello null: 0"));
        //verify(loggerMock, atLeast(1)).isDebugEnabled(); // fails
    }

    @Test
    public void testIsDebugEnabled_False() throws Exception {
        when(loggerMock.isDebugEnabled()).thenReturn(false);
        doNothing().when(loggerMock).debug(any(String.class));

        assertThat(service.getMessage(), is("Hello null: 0"));
        //verify(loggerMock, atLeast(1)).isDebugEnabled(); // fails
    }
}

在三叶草中,我显示了该if(logger.isDebugEnabled()){图块的100%覆盖率。但是,如果我尝试验证loggerMock

verify(loggerMock, atLeast(1)).isDebugEnabled();

我得到零互动。我也试过PowerMockito.verifyStatic(); 在,@Before但也有零互动。

Cobertura表示if(logger.isDebugEnabled()){尚未完成100%的工作,而Clover确实没有100%完成工作,但这似乎很奇怪,但是双方都同意验证失败。


问题答案:

@Mick,也尝试准备静态字段的所有者,例如:

@PrepareForTest({GoodbyeController.class, LoggerFactory.class})

EDIT1:我只是制作了一个小例子。首先是控制器:

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class Controller {
    Logger logger = LoggerFactory.getLogger(Controller.class);

    public void log() { logger.warn("yup"); }
}

然后测试:

import org.junit.Test;
import org.junit.runner.RunWith;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyString;
import static org.mockito.Mockito.verify;
import static org.powermock.api.mockito.PowerMockito.mock;
import static org.powermock.api.mockito.PowerMockito.mockStatic;
import static org.powermock.api.mockito.PowerMockito.when;

@RunWith(PowerMockRunner.class)
@PrepareForTest({Controller.class, LoggerFactory.class})
public class ControllerTest {

    @Test
    public void name() throws Exception {
        mockStatic(LoggerFactory.class);
        Logger logger = mock(Logger.class);
        when(LoggerFactory.getLogger(any(Class.class))).thenReturn(logger);

        new Controller().log();

        verify(logger).warn(anyString());
    }
}

注意进口!类路径中值得注意的库:Mockito,PowerMock,JUnit,logback-core,logback-clasic,slf4j

EDIT2:看来这是一个很普遍的问题,我想指出的是, 如果这些日志消息如此重要 并且需要进行测试,即它们是系统的功能/业务部分,
那么就引入一个真正的依赖关系,可以明确这些日志的功能将是整个系统设计中的更好 ,而不是依赖记录器的标准和技术类的静态代码。

为此,我建议Reporter使用诸如reportIncorrectUseOfYAndZForActionX或方法之类的东西来制作类似于=
类的东西reportProgressStartedForActionX。这将使使该功能对任何阅读代码的人可见。但这也将有助于实现测试,更改此特定功能的实现细节。

因此,您不需要像PowerMock这样的静态模拟工具。 我认为静态代码可能很好,但是一旦测试要求验证或模拟静态行为,就必须重构并引入明确的依赖关系。



 类似资料:
  • 我正在尝试使用JUnit、Mockito和PowerMock验证对的调用。 下面是我的测试用例: 下面是测试中的代码: 非常有趣的是,这段代码失败时出现:

  • 当我尝试使用mockito和powermock(在testng框架下使用)来模拟这些变量时,我遇到了一个问题 到目前为止我所做的 但是当我试图运行上面的代码时,我得到了以下错误: > 您使用以下任一方法存根:final/private/equals()/hashCode()方法。这些方法不能被截取/验证。不支持在非公共父类上声明的模拟方法。 在when()中,您不是在mock上调用method而是

  • 问题内容: 我试图遵循这个非常相似的问题的答案中提供的示例,但是它对我不起作用。我收到以下错误消息: 我需要一个简单的模拟实例。我不需要模拟任何方法。 这是我要模拟的课程: 我有以下TestNG设置: 问题答案: 我通过扩展PowerMockTestCase类来完成这项工作,该类为TestNG处理此类事情:

  • 我想为我拥有的一个类编写一个单元测试。这个类有一个公共方法,在公共方法内部有对同一个类中的私有方法的调用。我想模拟对那些私有方法的调用。类与此类似: 对于我的单元测试,我尝试将PowerMock与Mockito和TestNG一起使用。下面是我对测试SomePublicMethod的测试的尝试: 当我运行这个测试时,我会得到一个异常和一些提示: 我在网上看了一些例子,但是我还没有找到一个专门使用Po

  • 问题内容: 我有这样的情况 到目前为止我一直在嘲笑 现在我得到一个读者 但是当我执行此行时,我得到null并且无法前进 请告诉我如何嘲笑这个。请注意,我无法更改我的主要代码,因此在我的情况下,Mockito文档中存在的解决方案无效 测试码 问题答案: 要使此工作正常进行,您需要使用Powermockito来拦截构造函数调用(新的InputStreamReader(…),新的BufferedRead