当前位置: 首页 > 知识库问答 >
问题:

java中带有mockito的记录器

陶睿
2023-03-14

我在试着验证Mockito的记录器信息。

但是,我不能运行我的junit类来覆盖所有代码行。

你知道为什么吗?

    public class App {
      private static final Logger LOGGER = Logger.getLogger(App.class);

      public List<String> addToListIfSizeIsUnder3(final List<String> list, final String value) {
        if (list == null) {
            LOGGER.error("A null list was passed in");
            return null;
        }
        if (list.size() < 3) {
            list.add(value);
        } else {
            LOGGER.debug("The list already has {} entries"+ list.size());
        }
        return list;
    }
}
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;

import java.util.ArrayList;
import java.util.List;

import org.apache.log4j.Appender;
import org.apache.log4j.Level;
import org.apache.log4j.Logger;
import org.apache.log4j.spi.LoggingEvent;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Captor;
import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;

@RunWith(MockitoJUnitRunner.class)
public class AppTest {
    private App uut;
    @Mock
    private Appender mockAppender;
    @Captor
    private ArgumentCaptor<LoggingEvent> captorLoggingEvent;

    @Before
    public void setup() {
        uut = new App();

        Logger root = Logger.getRootLogger();
        root.addAppender(mockAppender);
        root.setLevel(Level.INFO);
    }

    /**
     * I want to test with over 3 elements.
     */
    @Test
    public void testWithOver3Element() {
        List<String> myList = new ArrayList<String>();
        myList.add("value 1");
        myList.add("value 2");
        myList.add("value 3");
        myList.add("value 4");
        List<String> outputList = uut.addToListIfSizeIsUnder3(myList, "some value");
        Assert.assertEquals(4, outputList.size());
        Assert.assertFalse(myList.contains("some value"));

try {
            verify(mockAppender, times(1)).doAppend(captorLoggingEvent.capture());
        } catch (AssertionError e) {
            e.printStackTrace();
        }

        LoggingEvent loggingEvent = captorLoggingEvent.getAllValues().get(0);
        Assert.assertEquals("The list already has {} entries", loggingEvent.getMessage());
        Assert.assertEquals(Level.DEBUG, loggingEvent.getLevel());
    }
}

需要但未调用:mockappender.doappend();->在AppTest.TestWithover3Element(AppTest.java:52)实际上,与这个模拟没有任何交互。

共有1个答案

东郭俊楠
2023-03-14

您可以做几件事来改进代码:

>

  • 切换到SLF4J。这将允许您编写一个接口的代码,并且不知道下面的日志实现(在您的例子中是apache log4j)。

    切换到slf4j将允许您在传递到日志记录框架时不必连接字符串-示例:

      null

    您正在尝试通过日志框架间接断言和捕获对对象的调用。这将是脆弱和容易出错的,因为您永远不知道日志记录框架中会在内部进行什么调用。仅模拟您的直接依赖关系。

    不要测试日志记录语句。这不是类的可见行为,它使测试变得脆弱和复杂。此外,使用ArrayList(即语言的一部分)来处理日志记录语句允许它们得到充分的执行,并且它们向控制台输出信息,这些信息可能有助于调试失败的测试。脆弱的一个例子是,如果更改日志记录语句以添加更多信息,或者可能向方法添加另一条日志记录语句,则该测试可能会无缘无故地中断。至少不要断言调用的次数,因为这将是非常脆弱的。

    以上所述,如果您必须测试与日志框架的交互--这里是运行并提供相同功能的代码的修改版本。这基本上是改进列表中的选项3-

    package com.spring.mockito;
    
    import static org.mockito.Mockito.spy;
    import static org.mockito.Mockito.times;
    import static org.mockito.Mockito.verify;
    import static org.mockito.Mockito.when;
    
    import org.apache.log4j.Logger;
    import org.junit.Assert;
    import org.junit.Before;
    import org.junit.Test;
    import org.junit.runner.RunWith;
    import org.mockito.Mock;
    import org.mockito.Mockito;
    import org.mockito.runners.MockitoJUnitRunner;
    
    import java.util.Arrays;
    import java.util.List;
    
    @RunWith(MockitoJUnitRunner.class)
    public class AppTest {
    
        // create a mock of the logger
        @Mock
        private Logger logger;
    
        private App uut;
    
        // Not needed - dont test something that gets called through something else
        // @Captor
        // private ArgumentCaptor<LoggingEvent> captorLoggingEvent;
    
        @Before
        public void setup() {
            // spy the class under test so we can override the logger method to return our mock logger
            uut = spy(new App());
            when(uut.logger()).thenReturn(logger);
    
            // Not needed test with the mock directly.
            // Logger root = Logger.getRootLogger();
            // root.addAppender(mockAppender);
            // root.setLevel(Level.DEBUG);
        }
    
        /**
         * I want to test with over 3 elements.
         */
        @Test
        public void testWithOver3Element() {
            List<String> myList = Arrays.asList("value 1", "value 2", "value 3", "value 4");
    
            List<String> outputList = uut.addToListIfSizeIsUnder3(myList, "some value");
    
            Assert.assertEquals(4, outputList.size());
            Assert.assertFalse(myList.contains("some value"));
            verify(logger, times(1)).debug("The list already has {} entries4");
    
            // not needed
            // try {
            // verify(mockAppender, times(1)).doAppend(captorLoggingEvent.capture());
            // } catch (AssertionError e) {
            // e.printStackTrace();
            // }
            //
            // LoggingEvent loggingEvent = captorLoggingEvent.getAllValues().get(0);
            // Assert.assertEquals("The list already has {} entries", loggingEvent.getMessage());
            // Assert.assertEquals(Level.DEBUG, loggingEvent.getLevel());
        }
    
        public static class App {
            private static final Logger LOGGER = Logger.getLogger(App.class);
    
            public List<String> addToListIfSizeIsUnder3(final List<String> list, final String value) {
                if (list == null) {
                    logger().error("A null list was passed in");
                    return null;
                }
                if (list.size() < 3) {
                    list.add(value);
                } else {
                    // if you use slf4j this concatenation is not needed
                    logger().debug("The list already has {} entries" + list.size());
                }
                return list;
            }
    
            // make a package private method for testing purposes to allow you to inject a mock
            Logger logger() {
                return LOGGER;
            }
        }
    }
    

  •  类似资料:
    • 问题内容: 我正在尝试模拟一些mongo类,以便不需要连接(相当标准的东西),但是以下代码给我带来了问题: 运行这个得到我: org.mockito.exceptions.misusing.InvalidUseOfMatchersException: 参数匹配器的无效使用! 预期0个匹配器,记录1个: 在… GridFileManagerTest.beforeClass(GridFileManag

    • 大家好,我需要为下面的示例创建AVRO模式; 当我按照建议更改所有者对象时,avro-tool返回错误。 ]} 测试:

    • 本文向大家介绍MongoDB将带有数组的记录转换为新集合中的多个记录,包括了MongoDB将带有数组的记录转换为新集合中的多个记录的使用技巧和注意事项,需要的朋友参考一下 为此,可以将$out与aggregate()和$undend一起使用。让我们用文档创建一个集合 在find()方法的帮助下显示集合中的所有文档- 这将产生以下输出- 以下是将具有数组的一个记录转换为新集合中的多个记录的查询- 这

    • 问题内容: 我的数据库表中具有以下格式的数据: 该列将来自该列的数据作为父记录。带有值的表示根项目。我需要编写查询以按以下顺序获取数据: 我需要得到根记录(与记录为0),然后是所有和这根记录,然后获得下根的记录,然后和在这个根记录等等。 问题答案: 我在这里提出的解决方案使用了物化路径的概念。以下是使用样本数据的实例化路径的示例。我希望它可以帮助您理解物化路径的概念: 每个节点都有一个实例化路径,

    • 问题内容: 我正在尝试获取相关表中某些记录类型的计数。我正在使用左联接。 因此,我有一个查询不太正确,并且正在返回正确的结果。正确的结果查询具有较高的执行成本。如果可以纠正结果,我想使用第一种方法。(请参阅http://sqlfiddle.com/#!15/7c20b/5/2) 我的目标是与所有这些人和他们活着的宠物种类一起归还一张桌子: 我使这个例子变得微不足道了。在我们的生产应用程序中(不是真