Qual è la differenza tra il beffardo e lo spionaggio quando si usa Mockito?

Quale sarebbe un caso d’uso per l’uso di una spia Mockito?

Mi sembra che ogni caso di utilizzo di spie possa essere gestito con una simulazione, usando callRealMethod.

Una differenza che posso vedere è che se vuoi che la maggior parte delle chiamate al metodo siano reali, salva alcune righe di codice per usare una simulazione contro una spia. È questo o mi manca l’immagine più grande?

La risposta è nella documentazione :

False parziali reali (dalla 1.8.0)

Infine, dopo molti dibattiti interni e discussioni sulla mailing list, a Mockito è stato aggiunto un supporto fittizio parziale. In precedenza abbiamo considerato i mock parziali come odori di codice. Tuttavia, abbiamo trovato un caso d’uso legittimo per le derisioni parziali – maggiori informazioni: qui

Prima della release 1.8 spy () non stava producendo veri e propri banchi parziali ed era fonte di confusione per alcuni utenti.

callRealMethod() stato introdotto dopo spy() , ma spy () è stato lasciato lì, ovviamente, per garantire la compatibilità con le versioni precedenti.

Altrimenti, hai ragione: tutti i metodi di una spia sono reali a meno che non vengano soppressi. Tutti i metodi di un mock vengono callRealMethod() meno che non callRealMethod() chiamato callRealMethod() . In generale, preferirei usare callRealMethod() , perché non mi obbliga a usare l’ doXxx().when() invece del tradizionale when().thenXxx()

Differenza tra una spia e una finta

Quando Mockito crea una simulazione, lo fa dalla class di un tipo, non da un’istanza reale. Il mock crea semplicemente un’istanza di shell bare-bones della class, interamente strumentata per tracciare le interazioni con esso. D’altra parte, la spia avvolgerà un’istanza esistente. Funzionerà allo stesso modo dell’istanza normale – l’unica differenza è che sarà anche strumentato per tracciare tutte le interazioni con esso.

Nell’esempio seguente, creiamo una simulazione della class ArrayList:

 @Test public void whenCreateMock_thenCreated() { List mockedList = Mockito.mock(ArrayList.class); mockedList.add("one"); Mockito.verify(mockedList).add("one"); assertEquals(0, mockedList.size()); } 

Come puoi vedere, l’aggiunta di un elemento nell’elenco fittizio non aggiunge nulla: chiama semplicemente il metodo senza altri effetti collaterali. Una spia d’altra parte si comporterà in modo diverso: in realtà chiamerà la vera implementazione del metodo add e aggiungerà l’elemento alla lista sottostante:

 @Test public void whenCreateSpy_thenCreate() { List spyList = Mockito.spy(new ArrayList()); spyList.add("one"); Mockito.verify(spyList).add("one"); assertEquals(1, spyList.size()); } 

Qui possiamo sicuramente dire che è stato chiamato il vero metodo interno dell’object perché quando chiamate il metodo size () ottenete la dimensione come 1, ma questo metodo size () non è stato deriso! Quindi da dove viene 1? Il metodo interno dimensione reale () viene chiamato come size () non è deriso (o stub) e quindi possiamo dire che la voce è stata aggiunta all’object reale.

Fonte: http://www.baeldung.com/mockito-spy + note automatiche.

Se c’è un object con 8 metodi e hai un test in cui vuoi chiamare 7 metodi reali e stubare un metodo hai due opzioni:

  1. Usando un simulatore dovresti impostarlo richiamando 7 callRealMethod e fermando un metodo
  2. Usando una spy devi configurarlo con lo stub di un metodo

La documentazione ufficiale su doCallRealMethod consiglia l’uso di una spia per i mock parziali.

Vedi anche javadoc spy (Object) per saperne di più sui mock parziali. Mockito.spy () è un metodo consigliato per creare simulazioni parziali. La ragione è che garantisce che i metodi reali vengano chiamati contro oggetti costruiti correttamente perché sei responsabile della costruzione dell’object passato al metodo spy ().

Spy può essere utile quando si desidera creare test unitari per il codice legacy .

Ho creato un esempio eseguibile qui https://www.surasint.com/mockito-with-spy/ , ne copio alcuni qui.

Se hai qualcosa come questo codice:

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

Potresti non aver bisogno di spiare perché puoi semplicemente deridere DepositMoneyService e WithdrawMoneyService.

Ma con alcuni, il 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ì, puoi passare al primo codice, ma l’API viene modificata. Se questo metodo viene utilizzato da molti posti, è necessario cambiarli tutti.

Alternativa è che puoi estrarre la dipendenza in questo modo:

  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 puoi usare la spia per iniettare la dipendenza in questo modo:

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