Zum Beispiel habe ich einen Handler:
@Component
public class MyHandler {
@AutoWired
private MyDependency myDependency;
public int someMethod() {
...
return anotherMethod();
}
public int anotherMethod() {...}
}
zum Testen möchte ich so etwas schreiben:
@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);
}
}
Es ruft jedoch anotherMethod()
auf, wenn ich versuche, es zu verspotten. Was soll ich mit myHandler
machen, um seine Methoden zu verspotten?
Der Grund für das Verspotten von MyHandler-Methoden kann zuallererst der folgende sein: Wir testen bereits anotherMethod()
und haben eine komplexe Logik. Warum müssen wir sie erneut testen (wie ein Teil von someMethod()
), wenn wir nur verify
aufrufen können, das aufgerufen wird?
Wir können es durch:
@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();
}
}
Hinweis: Im Falle eines 'Spionage'-Objekts müssen wir doReturn
anstelle von thenReturn
verwenden (kleine Erklärung ist hier )
In Ihrem Code testen Sie MyHandler überhaupt nicht. Sie möchten das, was Sie testen, nicht verspotten, sondern die eigentlichen Methoden aufrufen. Wenn MyHandler Abhängigkeiten hat, machen Sie sich über sie lustig.
Etwas wie das:
public interface MyDependency {
public int otherMethod();
}
public class MyHandler {
@AutoWired
private MyDependency myDependency;
public void someMethod() {
myDependency.otherMethod();
}
}
Und im Test:
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();
}
Es geht darum, die zu testende Methode wirklich aufzurufen, aber mögliche Abhängigkeiten zu simulieren (z. B. Aufrufmethode anderer Klassen).
Wenn diese anderen Klassen Teil Ihrer Anwendung sind, haben sie eigene Komponententests.
NOTEder obige Code könnte mit mehr Anmerkungen verkürzt werden, aber ich wollte es zur Erklärung noch deutlicher machen (und ich kann mich auch nicht erinnern, was die Anmerkungen sind :)