Mockito-spy vs mock

Mockito - je comprends qu'un espion appelle les méthodes réelles sur un objet, alors qu'une simulation appelle les méthodes sur l'objet double. Il faut aussi éviter les espions sauf s'il y a une odeur de code. Cependant, comment fonctionnent les espions et Quand dois-je les utiliser? Comment sont-ils différents des simulacres?

43
demandé sur Abhinav 2015-02-03 12:38:14

5 réponses

techniquement parlant, les deux "mocks" et "spies"sont une sorte spéciale de "double test".

Mockito fait malheureusement la distinction bizarre.

Une maquette en mockito est normal de se moquer dans d'autres cadres de moquerie (permet de couper les invocations, c'est-à-dire de retourner des valeurs spécifiques hors des appels de méthode).

Un espion dans mockito est une fantaisie partielle dans d'autres cadres de moquerie (une partie de l'objet sera moquée et une partie utilisera réel les appels de méthode).

49
répondu Crazyjavahacking 2017-09-13 16:04:29

j'ai créé un runable exemple ici https://www.surasint.com/mockito-with-spy/

j'en copie ici.

Si vous avez quelque chose comme ce code:

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

vous n'avez peut-être pas besoin de spy parce que vous pouvez simplement vous moquer DepositMoneyService et retirer Moneyservice.

mais avec du code d'héritage, la dépendance est dans le code comme ceci:

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

Oui, vous pouvez changer pour le premier code, mais alors API est changé. Si cette méthode est utilisée par de nombreux endroits, vous devez tous les changer.

Alternative est que vous pouvez extraire de la dépendance comme ceci:

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

Ensuite, vous pouvez utiliser l'espion de l'injecter la dépendance comme ceci:

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

Plus de détails dans le lien ci-dessus.

10
répondu Surasin Tancharoen 2018-07-21 16:37:11

Le meilleur endroit pour commencer est probablement les docs pour mockito.

sur une note générale le Mockito mock vous permet de créer des talons.

vous créeriez une méthode du talon si, par exemple, cette méthode fait une opération coûteuse. Dire, il obtient une connexion de base de données, récupère une valeur de la base de données et retourne à l'appelant. L'obtention de la connexion db peut prendre 30 secondes, ralentissant l'exécution de votre test au point où vous allez probablement contextualiser interrupteur (ou arrêt du test).

si la logique que vous testez ne se soucie pas de la connexion à la base de données, alors vous pouvez remplacer cette méthode par un talon qui renvoie une valeur codée dure.

l'Espion mockito vous permet de vérifier si une méthode appelle d'autres méthodes. Cela peut être très utile lorsque vous essayez d'obtenir du code d'héritage sous test.

il est utile si vous testez une méthode qui fonctionne à travers les effets secondaires, alors vous utiliserez un espion mockito. Ce délégués appelle à l'objet réel et vous permet de vérifier l'invocation de la méthode, le nombre de fois invoquées, etc.

7
répondu Jaimie Whiteside 2015-02-03 10:06:36

TL;DR version,

faux, il crée pour vous une instance de shell en os nu.

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

spy vous pouvez partiellement fictif sur un existant exemple

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

cas d'utilisation Typique pour l'Espion: la classe a un constructeur paramétré, vous souhaitez créer l'objet premier.

6
répondu del bao 2017-08-28 19:41:54

Les deux peuvent être utilisés pour simuler des méthodes ou des champs. La différence est que dans mock, vous créez un objet complet mock ou fake alors que dans spy, Il ya l'objet réel et vous espionner ou stubbing méthodes spécifiques de celui-ci.

alors que dans les objets espions, bien sûr, puisque c'est une méthode réelle, quand vous ne tapez pas la méthode, alors elle appellera le comportement de la méthode réelle. Si vous voulez changer et vous moquer de la méthode, alors vous devez la couper.

considérer l'exemple ci-dessous une comparaison.

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

Quand devez-vous utiliser mock ou spy? Si vous voulez être sûr et éviter d'appeler des services externes et que vous voulez juste tester la logique à l'intérieur de l'unité, utilisez mock. Si vous voulez appeler le service externe et effectuer l'appel de la dépendance réelle, ou simplement dire, vous voulez exécuter le programme tel qu'il est et juste des méthodes spécifiques de talon, puis utiliser l'Espion. C'est la différence entre espionner et se moquer à mockito.

5
répondu Vu Truong 2017-12-19 15:22:52