Мокито обход статического метода для тестирования

Мне нужно проверить метод handleIn(), используя Mockito.

Однако код должен вызвать этот устаревший код Util.getContextPDO, который является статическим методом.

Обратите внимание, что в тестовой среде этот Util.getContextPDO всегда возвращает Exception, и я намерен обойти этот Util.getContextPDO(), всегда возвращая фиктивный 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;
  } 
}

Первоначально я считал, что это возможно с помощью spy() класса "MyClass", поэтому я могу высмеять возвращаемое значение 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)));

}

Однако , когда (handler2.getIPDO()). thenReturn (pdo); бросает исключение, которое я хочу избежать (поскольку handler2.getIPDO()), похоже, вызывает реальный метод.

Любая идея о том, как протестировать эту часть кода?

Ответ 1

Изменено мое тестирование:

@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.

Ответ 2

Хорошая техника избавления от статических вызовов от стороннего API скрывает статический вызов за интерфейсом.

Скажем, вы создаете этот интерфейс:

interface IPDOFacade {

    IPDO getContextPDO();
}

и имеет реализацию по умолчанию, которая просто вызывает статический метод для стороннего API:

class IPDOFacadeImpl implements IPDOFacade {

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

Тогда это просто вопрос ввода зависимости от интерфейса в MyClass и использования интерфейса, а не стороннего 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 test вы можете легко высмеять свой собственный интерфейс, заглушить его любым способом, как вам нравится, и ввести его в тестируемый блок.

Это

  • избегает необходимости приватного частного пакета.
  • делает ваши тесты более читабельными, избегая частичного издевательств.
  • применяется инверсия элемента управления.
  • отделяет ваше приложение от конкретной сторонней библиотеки.

Ответ 3

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

На самом деле вызовет метод, а затем вернет pdo независимо.

В то время как:

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

Вернет pdo без вызова метода getIPDO().