使用PowerMock和Mockito模拟Logger和LoggerFactory

编程入门 行业动态 更新时间:2024-10-19 10:25:25
本文介绍了使用PowerMock和Mockito模拟Logger和LoggerFactory的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧! 问题描述

我要模拟以下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)); ... }

我想知道:

  • 我可以模拟静态LoggerFactory.getLogger()以便用于任何课程吗?
  • 我似乎只能在@Before中运行when(loggerMock.isDebugEnabled()).thenReturn(true);,因此我似乎无法更改每种方法的特征.有办法解决吗?
  • 修改搜索结果:

    我以为我已经尝试过了,但是没有用:

    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确实做到了,但双方都同意验证失败,这似乎很奇怪.

    解决方案

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

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

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

    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

    似乎是一个很普遍的问题,我想指出如果这些日志消息如此重要并且需要进行测试,即它们是功能/业务的一部分系统然后引入一个真正的依赖关系,以明确这些日志是功能,这在整个系统设计中会好得多,而不是依赖记录器的标准和技术类的静态代码. /p>

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

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

    I have the following Logger I want to mock out, but to validate log entries are getting called, not for the content.

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

    I want to Mock ANY class that is used for LoggerFactory.getLogger() but I could not find out how to do that. This is what I ended up with so far:

    @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)); ... }

    I would like to know:

  • Can I Mock the static LoggerFactory.getLogger() to work for any class?
  • I can only seem to run when(loggerMock.isDebugEnabled()).thenReturn(true); in the @Before and thus I cannot seem to change the characteristics per method. Is there a way around this?
  • Edit findings:

    I thought I tried this already and it didnt work:

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

    But thank you, as it did work.

    However I have tried countless variations to:

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

    I cannot get the loggerMock to change its behavior outside of @Before but this only happens with Coburtura. With Clover, the coverage shows 100% but there is still an issue either way.

    I have this simple class:

    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!"; } ... }

    Then I have this test:

    @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 } }

    In clover I show 100% coverage of the if(logger.isDebugEnabled()){ block. But if I try to verify the loggerMock:

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

    I get zero interactions. I also tried PowerMockito.verifyStatic(); in @Before but that also has zero interactions.

    This just seems strange that Cobertura shows the if(logger.isDebugEnabled()){ as being not 100% complete, and Clover does, but both agree the verification fails.

    解决方案

    @Mick, try to prepare the owner of the static field too, eg :

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

    EDIT1 : I just crafted a small example. First the controller :

    import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class Controller { Logger logger = LoggerFactory.getLogger(Controller.class); public void log() { logger.warn("yup"); } }

    Then the test :

    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()); } }

    Note the imports ! Noteworthy libs in the classpath : Mockito, PowerMock, JUnit, logback-core, logback-clasic, slf4j

    EDIT2 : As it seems to be a popular question, I'd like to point out that if these log messages are that important and require to be tested, i.e. they are feature / business part of the system then introducing a real dependency that make clear theses logs are features would be a so much better in the whole system design, instead of relying on static code of a standard and technical classes of a logger.

    For this matter I would recommend to craft something like= a Reporter class with methods such as reportIncorrectUseOfYAndZForActionX or reportProgressStartedForActionX. This would have the benefit of making the feature visible for anyone reading the code. But it will also help to achieve tests, change the implementations details of this particular feature.

    Hence you wouldn't need static mocking tools like PowerMock. In my opinion static code can be fine, but as soon as the test demands to verify or to mock static behavior it is necessary to refactor and introduce clear dependencies.

    更多推荐

    使用PowerMock和Mockito模拟Logger和LoggerFactory

    本文发布于:2023-10-31 04:38:44,感谢您对本站的认可!
    本文链接:https://www.elefans.com/category/jswz/34/1545031.html
    版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
    本文标签:Mockito   PowerMock   LoggerFactory   Logger

    发布评论

    评论列表 (有 0 条评论)
    草根站长

    >www.elefans.com

    编程频道|电子爱好者 - 技术资讯及电子产品介绍!