Mockito绕过静态方法进行测试

新手上路,请多包涵

我需要使用 Mockito 测试 handleIn() 方法。

但是,代码需要调用此遗留代码 Util.getContextPDO,这是一个静态方法。

请注意,在测试环境中,此 Util.getContextPDO 始终返回异常,我打算通过始终返回虚拟 IPDO 来绕过此 Util.getContextPDO()。

 public class MyClass {
  public IPDO getIPDO()
  {
    return Util.getContextPDO(); // note that Util.getContextPDO() is a static, not mockable.
  }

  public String handleIn(Object input) throws Throwable
  {
    String result = "";
    IPDO pdo = getIPDO();

    // some important business logic.

    return result;
  }
}

最初我认为这可以通过使用“MyClass”类的 spy() 来实现,因此我可以模拟 getIPDO() 的返回值。下面是我最初使用 spy() 的努力

@Test
public void testHandleIn() throws Exception
{
    IPDO pdo = new PDODummy();

    MyClass handler = new MyClass ();
    MyClass handler2 = spy(handler);

    when(handler2.getIPDO()).thenReturn(pdo);
    PDOUtil.setPDO(pdo, LogicalFieldEnum.P_TX_CTGY, "test123");
    IPDO pdoNew = handler2.getIPDO();

    Assert.assertEquals("test123,(PDOUtil.getValueAsString(pdoNew, LogicalFieldEnum.P_TX_CTGY)));

}

然而 when(handler2.getIPDO()).thenReturn(pdo); 正在抛出我想避免的异常(因为 handler2.getIPDO() )似乎调用了真正的方法。

关于如何测试这部分代码的任何想法?

原文由 Rudy 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 678
2 个回答

将我的测试更改为:

 @Test
public void testHandleIn() throws Exception
{
  IPDO pdo = new PDODummy();

  MyClass handler = new MyClass ();
  MyClass handler2 = spy(handler);

  doReturn(pdo ).when( handler2 ).getIPDO();
  PDOUtil.setPDO(pdo, LogicalFieldEnum.P_TX_CTGY, "test123");
  IPDO pdoNew = handler2.getIPDO();

  Assert.assertEquals("test123,(PDOUtil.getValueAsString(pdoNew, LogicalFieldEnum.P_TX_CTGY)));

}

阅读 Effective Mockito 后解决。

原文由 Rudy 发布,翻译遵循 CC BY-SA 3.0 许可协议

摆脱对 3rd 方 API 的静态调用的一种好方法是将静态调用隐藏在接口后面。

假设您制作了这个界面:

 interface IPDOFacade {

    IPDO getContextPDO();
}

并有一个默认实现,它只调用 3rd 方 API 上的静态方法:

 class IPDOFacadeImpl implements IPDOFacade {

    @Override
    public IPDO getContextPDO() {
        return Util.getContextPDO();
    }
}

然后只需将对接口的依赖项注入 MyClass 并使用接口,而不是直接使用第 3 方 API:

 public class MyClass {

    private final IPDOFacade ipdoFacade;

    public MyClass(IPDOFacade ipdoFacade) {
        this.ipdoFacade = ipdoFacade;
    }

    private IPDO getIPDO() {
        return ipdoFacade.getContextPDO();
    }

    public String handleIn(Object input) throws Throwable
    {
        String result = "";
        IPDO pdo = getIPDO();

        someImportantBusinessLogic(pdo);

        return result;
    }

    ...

}

在你的单元测试中,你可以轻松地模拟你自己的接口,以你喜欢的任何方式存根并将它注入到被测单元中。

这个

  • 避免了将私有方法包设为私有的需要。
  • 通过避免部分模拟使您的测试更具可读性。
  • 应用控制反转。
  • 将您的应用程序与特定的第 3 方库分离。

原文由 bowmore 发布,翻译遵循 CC BY-SA 4.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题