2015-02-03 13 views
37

Mockito - Capisco che una spia chiami i metodi reali su un oggetto, mentre un finto chiama i metodi sul doppio oggetto. Anche le spie vanno evitate a meno che non ci sia un odore di codice. Tuttavia, come funzionano le spie e quando dovrei effettivamente usarle? Come sono diversi dai mock?Mockito - spy vs mock

+1

possibile duplicato di [mockito mock vs. spy] (http://stackoverflow.com/questions/15052984/mockito-mock-vs-spy) – rds

+0

Possibile duplicato di [Mocking vs. Spying in mocking frameworks] (http: //stackoverflow.com/questions/12827580/mocking-vs-spying-in-mocking-frameworks) – PenguinEngineer

risposta

6

Il miglior punto di partenza è probabilmente the docs for mockito.

In generale, il mockito mock consente di creare stub.

Si creerebbe un metodo di stub se, ad esempio, tale metodo esegue un'operazione costosa. Supponiamo, ottiene una connessione al database, recupera un valore dal database e lo restituisce al chiamante. Ottenere la connessione db potrebbe richiedere 30 secondi, rallentando l'esecuzione del test fino al punto in cui è probabile che il contesto cambierà (o smetterà di eseguire il test).

Se la logica che si sta testando non interessa la connessione al database, è possibile sostituire tale metodo con uno stub che restituisce un valore hard coded.

La spia di mockito consente di verificare se un metodo chiama altri metodi. Questo può essere molto utile quando si cerca di ottenere il codice legacy sotto test.

È utile se si sta testando un metodo che funziona con effetti collaterali, quindi si utilizzerà una spia mockito. Questo delega le chiamate all'oggetto reale e consente di verificare l'invocazione del metodo, il numero di volte richiamate, ecc.

35

Tecnicamente parlando sia "mock" che "spies" sono un tipo speciale di "test double".

Mockito fa purtroppo la distinzione.

Un simulato in mockito è un normale simulato in altri framework di derisione (consente di stub invocazioni, vale a dire, restituire valori specifici di chiamate di metodo).

Una spia in mockito è un simulato parziale in altri framework di derisione (parte dell'oggetto verrà derisa e parte userà le invocazioni del metodo reale).

+1

Quindi quando usare uno sull'altro? –

+0

@IgorGanapolsky: dipende dal tuo caso d'uso. :-) – Sipty

8

ho creato un esempio ruanble qui https://www.surasint.com/mockito-with-spy/

copio alcuni di qui.

Se hai qualcosa di simile a questo codice:

public void transfer( DepositMoneyService depositMoneyService, WithdrawMoneyService withdrawMoneyService, 
      double amount, String fromAccount, String toAccount){ 
    withdrawMoneyService.withdraw(fromAccount,amount); 
    depositMoneyService.deposit(toAccount,amount); 
} 

Potrebbe essere non è necessario spia perché si può solo DepositMoneyService finta e WithdrawMoneyService.

Ma con un po 'di codice legacy, la dipendenza è nel codice come questo:

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); 
    } 

Sì, è possibile modificare al primo codice, ma poi API è cambiato. Se questo metodo viene utilizzato da molti posti, è necessario cambiarli tutti.

alternativa è che si può estrarre la dipendenza come questo:

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(); 
    } 

quindi è possibile utilizzare la spia del iniettare la dipendenza come questo:

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(); 

Maggiori dettagli nel link qui sopra.

2

TL; DR versione,

Con finta, si crea un'istanza della shell bare-bone per voi.

List<String> mockList = Mockito.mock(ArrayList.class); 

Con spia si può parzialmente finta su un'istanza esistente

List<String> spyList = Mockito.spy(new ArrayList<String>()); 

caso d'uso tipica per Spy: la classe ha un costruttore con parametri, si desidera creare l'oggetto prima.

0

Entrambi possono essere utilizzati per simulare metodi o campi. La differenza sta nel fatto che in finta si sta creando un oggetto falso o finto completo mentre si è nella spia, c'è l'oggetto reale e si sta semplicemente spiando o stubando metodi specifici di esso.

Mentre negli oggetti spia, ovviamente, poiché si tratta di un metodo reale, quando non si esegue lo stub del metodo, chiamerà il comportamento del metodo reale. Se vuoi cambiare e prendere in giro il metodo, allora devi fermarlo.

Considerare l'esempio seguente come confronto.

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)); 
    } 
} 

Quando si usa il mock o la spia? Se vuoi essere sicuro ed evitare di chiamare servizi esterni e vuoi solo testare la logica all'interno dell'unità, usa il mock. Se si desidera chiamare il servizio esterno ed eseguire chiamate di dipendenza reale, o semplicemente dire, si desidera eseguire il programma così com'è e solo mozzare metodi specifici, quindi utilizzare spy. Quindi questa è la differenza tra spia e finto in mockito.