Mockito绕过静态方法进行测试

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

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

请注意,在测试环境中,此Util.getContextPDO始终返回Exception,并且我打算通过始终返回虚拟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); 抛出我想要避免的exception(因为handler2.getIPDO())似乎调用了真正的方法。

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

在第三方API上摆脱静态调用的一种好方法是隐藏接口后面的静态调用。

假设您创建此界面:

 interface IPDOFacade { IPDO getContextPDO(); } 

并有一个默认实现,只需调用第三方API上的静态方法:

 class IPDOFacadeImpl implements IPDOFacade { @Override public IPDO getContextPDO() { return Util.getContextPDO(); } } 

然后,只需将接口dependency injectionMyClass并使用接口,而不是直接使用第三方API:

 public class MyClass { private final IPDOFacade ipdoFacade; public MyClass(IPDOFacade ipdoFacade) { this.ipdoFacade = ipdoFacade; } public String handleIn(Object input) throws Throwable { String result = ""; IPDO pdo = getIPDO(); someImportantBusinessLogic(pdo); return result; } ... } 

在unit testing中,您可以轻松地模拟自己的界面,以任何您喜欢的方式存根,并将其注入被测单元。

这个

  • 避免需要将私有方法包私有化。
  • 通过避免部分模拟,使您的测试更具可读性。
  • 适用于控制倒置。
  • 将您的应用程序与特定的第三方库分离。

将我的测试更改为:

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

阅读完有效的Mockito后解决了。

 when(handler2.getIPDO()).thenReturn(pdo); 

实际上会调用该方法,然后返回pdo

鉴于:

 doReturn(pdo).when(handler2).getIPDO(); 

将在不调用getIPDO()方法的情况下返回pdo。