繁体   English   中英

static 字段的 Mocking 是 class 和 Mockito

[英]Mocking of static field that is a class with Mockito

我的 Utils class 有一个依赖于外部资源(例如,数据库连接)的 init 方法,我没有成功 mocking 和 Mockito。Utils 似乎可以跨我的应用程序实例共享,因此被声明为 static(即 class变量)在

public class EmailNotificationWorkItemHandler extends AbstractLogOrThrowWorkItemHandler { 
   private static Utils utils = new Utils();
  
   public void executeWorkItem(WorkItem workItem, WorkItemManager manager) {
 
   // Throw an error due to many missing parameters on the workitem
   String id= (String) workItem.getParameter("ID");

...
     try { 
         RequiredParameterValidator.validate(this.getClass(), workItem);
...
     } catch (Throwable e) {
         utils.insertErrors(id, errorCode, errorMessage, e.getStackTrace(), -1L);  // testing this method called
      }    
    
 ...
      }
  

我意识到我可以为 Utils 使用依赖注入,但我正在避免使用Spring。 关于mocking static 字段的帖子让我觉得我很接近:

@Test
public void executeWorkItemMissingParametersTest() {
      
      Utils mockUtils = mock(Utils.class);
      WorkItemManager mockWorkItemMgr = mock(WorkItemManager.class);
      EmailNotificationWorkItemHandler mockWorkItemHandler =  mock(EmailNotificationWorkItemHandler.class);
      
      doAnswer(new Answer<Void>() {
          public Void answer(InvocationOnMock invocation) {
                 Object[] args = invocation.getArguments();
                 System.out.println("called with arguments: " + Arrays.toString(args));
                 return null;
            }         
      }).when(mockUtils).insertErrors(any(), any(), any(), any(), anyLong());
      
      
      try {
        doAnswer(new Answer<Void>() {          // Unfinished stubbing detected
              public Void answer(InvocationOnMock invocation) {
                     return null;
                }         
          }).when(mockUtils);
          Utils.init();
      } catch (Exception e) {
        System.out.println("In mocking of Utils.init() " + e.getLocalizedMessage());
      }
      
      WorkItemImpl workItem = new WorkItemImpl();
      workItem.setParameter("ID", "1111-AAAA");
      // Lots of required parameters removed to cause an exception and insertErrors to be called
      
      mockWorkItemHandler.executeWorkItem(workItem, mockWorkItemMgr);
      verify(mockUtils).insertErrors(any(), any(), contains("RequiredParameterValidator"), any(), anyLong());
   }

但是在 mockWorkItemHandler 中使用和调用了一个真实的 Utils 实例 - 而不是模拟的 Utils - 并且在上面标记的地方发生了“检测到未完成的存根”异常。 我的目标是测试代码中注释的 utils.insertErrors 的调用,并在没有 Utils 的副作用的情况下执行此操作。 我在模拟中缺少什么(1)使用模拟的 Utils(没有副作用,例如数据库连接)和(2)测试调用 mockWorkItemHandler 的 utils.insertErrors 来记录丢失的参数?

请注意,我已经展示了似乎是 EmailNotificationWorkItemHandler 和 Utils 的所有相关部分。

这是一个使用 mockito 内联的 mocking 构造调用的简单示例。 为了启用 mockito-inline,您可以参考此答案,因为 mockito 默认关闭它。您可以在您的用例中使用它,它应该可以解决您的问题。

消费者 Class

public class ConsumerClass {

    Logger logger = LoggerFactory.getLogger(ConsumerClass.class);

    private static final Utils utils = new Utils();

    public String callUtilMethod(){
        logger.info("ConsumerClass callUtilMethod");
        return utils.helloWorld();
    }

}

工具

public class Utils {

    Logger logger = LoggerFactory.getLogger(Utils.class);

    public String helloWorld() {
        logger.info("Utils class Hello World");
        return "This is from Utils";
    }
}

测试用例

 @Test
    void testConsumerClass() {
        try (MockedConstruction<Utils> mocked = Mockito.mockConstruction(Utils.class, (mock, context) -> {
            Mockito.when(mock.helloWorld()).thenReturn("This is from Mock");
        })) {
            ConsumerClass consumerClass = new ConsumerClass();
            Assertions.assertEquals("This is from Mock", consumerClass.callUtilMethod());
        }
    }

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM