使用 Mockito 模拟类的静态字段

问题描述 投票:0回答:1

我的 Utils 类有一个依赖于外部资源(例如数据库连接)的 init 方法,我无法使用 Mockito 模拟该方法。 Utils 似乎可以在我的应用程序实例之间共享,因此在

中声明为静态(即类变量)
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。 帖子 关于 模拟静态字段让我感觉我很接近:

@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 的所有相关部分。

java unit-testing mockito powermockito
1个回答
0
投票

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

消费类

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());
        }
    }
© www.soinside.com 2019 - 2024. All rights reserved.