Mockito - Rozumiem, że szpieg nazywa prawdziwe metody na obiekcie, podczas gdy pozorowane metody połączeń na podwójnym obiekcie. Trzeba też unikać szpiegów, chyba że istnieje zapach kodu. Jak jednak działają szpiedzy i kiedy powinienem ich używać? Czym różnią się od makiet?Mockito - spy vs mock
Odpowiedz
Najlepszym miejscem do rozpoczęcia jest prawdopodobnie the docs for mockito.
Ogólnie rzecz biorąc, mockito pozwala tworzyć odcinki.
Można utworzyć metodę pośredniczącą, jeśli na przykład ta metoda wykonuje kosztowną operację. Powiedzmy, że pobiera połączenie z bazą danych, pobiera wartość z bazy danych i zwraca ją do dzwoniącego. Uzyskanie połączenia db może potrwać 30 sekund, co spowolni wykonywanie testów do momentu, w którym prawdopodobnie nastąpi zmiana kontekstu (lub przestaniesz przeprowadzać test).
Jeśli logika, którą testujesz, nie dba o połączenie z bazą danych, możesz zastąpić tę metodę kodem, który zwraca zakodowaną wartość.
Szpieg mockito pozwala sprawdzić, czy metoda wywołuje inne metody. Może to być bardzo przydatne podczas próby przetestowania starszego kodu.
Jest to przydatne, jeśli testujesz metodę, która działa poprzez efekty uboczne, wtedy użyłbyś szpiega mockito. To delegaci wzywają do rzeczywistego obiektu i umożliwiają weryfikację inwokacji metody, wielokrotną inwokację itp.
Z technicznego punktu widzenia zarówno "mocks", jak i "szpiedzy" są szczególnym rodzajem "testu podwójnego".
Mockito niestety robi dziwne rozróżnienie.
Maniak w mockito to normalna egzekucja w innych szyderczych frameworkach (pozwala wywoływać wywołania, czyli zwracać określone wartości z wywołań metod).
Szpieg w mockito to częściowa próba w innych szyderczych ramach (część obiektu będzie wyśmiewana, a część użyje prawdziwych wywołań metod).
Więc kiedy używać jednego na drugim? –
@IgorGanapolsky: to zależy od twojego przypadku użycia. :-) – Sipty
Stworzyłem ruanble przykładem https://www.surasint.com/mockito-with-spy/
skopiować niektóre z nich tutaj.
Jeśli masz coś takiego kodu:
public void transfer( DepositMoneyService depositMoneyService, WithdrawMoneyService withdrawMoneyService,
double amount, String fromAccount, String toAccount){
withdrawMoneyService.withdraw(fromAccount,amount);
depositMoneyService.deposit(toAccount,amount);
}
Być może nie trzeba szpiega, ponieważ można tylko mock DepositMoneyService i WithdrawMoneyService.
Ale z jakiegoś starszych kod, zależność jest w kodzie jak poniżej:
public void transfer(String fromAccount, String toAccount, double amount){
this.depositeMoneyService = new DepositMoneyService();
this.withdrawMoneyService = new WithdrawMoneyService();
withdrawMoneyService.withdraw(fromAccount,amount);
depositeMoneyService.deposit(toAccount,amount);
}
Tak, można przejść do pierwszego kodu, ale potem API zostało zmienione. Jeśli ta metoda jest używana w wielu miejscach, musisz je wszystkie zmienić.
alternatywna jest to, że można wyodrębnić zależność się tak:
public void transfer(String fromAccount, String toAccount, double amount){
this.depositeMoneyService = proxyDepositMoneyServiceCreator();
this.withdrawMoneyService = proxyWithdrawMoneyServiceCreator();
withdrawMoneyService.withdraw(fromAccount,amount);
depositeMoneyService.deposit(toAccount,amount);
}
DepositMoneyService proxyDepositMoneyServiceCreator() {
return new DepositMoneyService();
}
WithdrawMoneyService proxyWithdrawMoneyServiceCreator() {
return new WithdrawMoneyService();
}
Następnie można użyć szpieg z wstrzyknąć zależność tak:
DepositMoneyService mockDepositMoneyService = mock(DepositMoneyService.class);
WithdrawMoneyService mockWithdrawMoneyService = mock(WithdrawMoneyService.class);
TransferMoneyService target = spy(new TransferMoneyService());
doReturn(mockDepositMoneyService)
.when(target).proxyDepositMoneyServiceCreator();
doReturn(mockWithdrawMoneyService)
.when(target).proxyWithdrawMoneyServiceCreator();
Więcej szczegółów w linku powyżej.
TL; DR wersja,
Z udawanym, tworzy gołe kości instancji powłoki dla Ciebie.
List<String> mockList = Mockito.mock(ArrayList.class);
może
Z szpiega częściowego makiety na istniejący przykład
List<String> spyList = Mockito.spy(new ArrayList<String>());
Typowy przypadek użycia dla Spy: klasa ma sparametryzowanego konstruktora, chcesz utworzyć obiekt jako pierwszy.
Obie mogą być używane do fałszywych metod lub pól. Różnica polega na tym, że w fałszywym przypadku tworzysz kompletny, fałszywy lub fałszywy obiekt, podczas gdy w szpiegu znajduje się prawdziwy obiekt, a ty po prostu szpiegujesz lub upuszczasz konkretne metody.
Podczas gdy w obiektach szpiegowskich, oczywiście, ponieważ jest to prawdziwa metoda, gdy nie upraszczasz metody, wówczas wywoła ona prawdziwe zachowanie metody. Jeśli chcesz zmienić i wyśmiać metodę, musisz ją zamknąć.
Weź pod uwagę przykład poniżej jako porównanie.
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.Spy;
import org.mockito.runners.MockitoJUnitRunner;
import java.util.ArrayList;
import java.util.List;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.when;
@RunWith(MockitoJUnitRunner.class)
public class MockSpy {
@Mock
private List<String> mockList;
@Spy
private List<String> spyList = new ArrayList();
@Test
public void testMockList() {
//by default, calling the methods of mock object will do nothing
mockList.add("test");
Mockito.verify(mockList).add("test");
assertEquals(0, mockList.size());
assertNull(mockList.get(0));
}
@Test
public void testSpyList() {
//spy object will call the real method when not stub
spyList.add("test");
Mockito.verify(spyList).add("test");
assertEquals(1, spyList.size());
assertEquals("test", spyList.get(0));
}
@Test
public void testMockWithStub() {
//try stubbing a method
String expected = "Mock 100";
when(mockList.get(100)).thenReturn(expected);
assertEquals(expected, mockList.get(100));
}
@Test
public void testSpyWithStub() {
//stubbing a spy method will result the same as the mock object
String expected = "Spy 100";
//take note of using doReturn instead of when
doReturn(expected).when(spyList).get(100);
assertEquals(expected, spyList.get(100));
}
}
Kiedy używasz makiety lub szpiega? Jeśli chcesz być bezpieczny i unikać dzwonienia do zewnętrznych serwisów i po prostu chcesz przetestować logikę wewnątrz urządzenia, użyj mocku. Jeśli chcesz połączyć się z usługą zewnętrzną i wykonać wywołanie rzeczywistej zależności lub po prostu powiedzieć, chcesz uruchomić program w obecnej postaci i po prostu użyć określonych metod, użyj szpiega. Taka jest różnica między szpiegiem a makietą w mockito.
możliwy duplikat [mockito mock vs. spy] (http://stackoverflow.com/questions/15052984/mockito-mock-vs-spy) – rds
Możliwy duplikat [szyderstwa kontra szpiegostwo w szyderczych ramach] (http: //stackoverflow.com/questions/12827580/mocking-vs-spying-in-mocking-frameworks) – PenguinEngineer