2015-02-03 22 views
37

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

+1

możliwy duplikat [mockito mock vs. spy] (http://stackoverflow.com/questions/15052984/mockito-mock-vs-spy) – rds

+0

Możliwy duplikat [szyderstwa kontra szpiegostwo w szyderczych ramach] (http: //stackoverflow.com/questions/12827580/mocking-vs-spying-in-mocking-frameworks) – PenguinEngineer

Odpowiedz

6

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.

35

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

+1

Więc kiedy używać jednego na drugim? –

+0

@IgorGanapolsky: to zależy od twojego przypadku użycia. :-) – Sipty

8

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.

2

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.

0

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.