Mockito bypass static method for testing

你。 提交于 2020-01-10 02:34:24

问题


I need to test handleIn() method using Mockito.

However the code need to call this legacy code Util.getContextPDO which is a static method.

Note that in testing environment this Util.getContextPDO is always returns Exception, and I intend to bypass this Util.getContextPDO() by always return a dummy IPDO.

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

Initially I thought this achieveable by using spy() of the class "MyClass", so I can mock the return value of getIPDO(). Below is my initial effort using 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)));

}

However the when(handler2.getIPDO()).thenReturn(pdo); is throwing the Exception that I want to avoid ( because handler2.getIPDO() ) seems to call the real method.

Any idea on how to test this part of code?


回答1:


Changed my testing to :

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

}

Solved after reading Effective Mockito.




回答2:


A good technique for getting rid of static calls on 3rd party API is hiding the static call behind an interface.

Let's say you make this interface :

interface IPDOFacade {

    IPDO getContextPDO();
}

and have a default implementation that simply calls the static method on the 3rd party API :

class IPDOFacadeImpl implements IPDOFacade {

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

Then it is simply a matter of injecting a dependency on the interface into MyClass and using the interface, rather than the 3rd party API directly :

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

    ...

}

In your unit test, you can then easily mock your own interface, stub it any way you like and inject it into the unit under test.

This

  • avoids the need to make private methods package private.
  • makes your tests more readable by avoiding partial mocking.
  • applies inversion of control.
  • decouples your application from a specific 3rd party library.



回答3:


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

Will actually call the method and then return pdo regardless.

Whereas:

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

Will return pdo without calling the getIPDO() method.



来源:https://stackoverflow.com/questions/14065515/mockito-bypass-static-method-for-testing

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!