Как я могу издеваться над методами класса @InjectMocks?
Например, у меня есть обработчик:
@Component
public class MyHandler {
@AutoWired
private MyDependency myDependency;
public int someMethod() {
...
return anotherMethod();
}
public int anotherMethod() {...}
}
чтобы проверить его, я хочу написать что-то вроде этого:
@RunWith(MockitoJUnitRunner.class}
class MyHandlerTest {
@InjectMocks
private MyHandler myHandler;
@Mock
private MyDependency myDependency;
@Test
public void testSomeMethod() {
when(myHandler.anotherMethod()).thenReturn(1);
assertEquals(myHandler.someMethod() == 1);
}
}
Но он на самом деле называет anotherMethod()
всякий раз, когда я пытаюсь его высмеять. Что делать с myHandler
, чтобы издеваться над его методами?
Ответы
Ответ 1
Прежде всего, причина для издевательских методов MyHandler может быть следующей: мы уже тестировали anotherMethod()
и у нее сложная логика, поэтому зачем нам ее снова тестировать (например, часть someMethod()
), если мы можем просто verify
, что он звонит?
Мы можем сделать это через:
@RunWith(MockitoJUnitRunner.class}
class MyHandlerTest {
@Spy
@InjectMocks
private MyHandler myHandler;
@Mock
private MyDependency myDependency;
@Test
public void testSomeMethod() {
doReturn(1).when(myHandler).anotherMethod();
assertEquals(myHandler.someMethod() == 1);
verify(myHandler, times(1)).anotherMethod();
}
}
Примечание: в случае объекта "шпионаж" нам нужно использовать doReturn
вместо thenReturn
(небольшое объяснение здесь)
Ответ 2
В вашем коде вы вообще не тестируете MyHandler. Вы не хотите издеваться над тем, что вы тестируете, вы хотите назвать его фактические методы. Если у MyHandler есть зависимости, вы издеваетесь над ними.
Что-то вроде этого:
public interface MyDependency {
public int otherMethod();
}
public class MyHandler {
@AutoWired
private MyDependency myDependency;
public void someMethod() {
myDependency.otherMethod();
}
}
И в тесте:
private MyDependency mockDependency;
private MyHandler realHandler;
@Before
public void setup() {
mockDependency = Mockito.mock(MyDependency.class);
realHandler = new MyHandler();
realhandler.setDependency(mockDependency); //but you might Springify this
}
@Test
public void testSomeMethod() {
//specify behaviour of mock
when(mockDependency.otherMethod()).thenReturn(1);
//really call the method under test
realHandler.someMethod();
}
Суть в том, чтобы действительно вызвать тестируемый метод, но высмеять любые зависимости, которые они могут иметь (например, метод вызова других классов)
Если эти другие классы являются частью вашего приложения, тогда у них будут свои собственные модульные тесты.
ПРИМЕЧАНИЕ приведенный выше код может быть сокращен с помощью дополнительных комментариев, но я хотел бы сделать его более явным для объяснения (а также не могу вспомнить, что представляют собой аннотации:))