Мокито обход статического метода для тестирования
Мне нужно проверить метод 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()
.