web-dev-qa-db-fra.com

Mockito - Spy vs Mock

Mockito - Je comprends qu'un espion appelle les vraies méthodes sur un objet, tandis qu'un faux appelle des méthodes sur le double objet. Les espions sont également à éviter sauf s’il ya une odeur de code . Cependant, comment fonctionnent-ils et quand dois-je les utiliser réellement?

53
Abhinav

Techniquement parlant, les "simulacres" et les "espions" constituent un type spécial de "test double".

Mockito fait malheureusement la distinction bizarre.

Un mock in mockito est un mock normal dans d'autres frameworks moqueurs (vous permet de remplacer des invocations; c'est-à-dire, renvoyer des valeurs spécifiques en dehors des appels de méthodes).

Un espion dans mockito est une réplique partielle dans d'autres frameworks moqueurs (une partie de l'objet sera moquée et une partie utilisera de véritables invocations de méthode).

60
Crazyjavahacking

J'ai créé un exemple exécutable ici https://www.surasint.com/mockito-with-spy/

J'en copie une partie 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 d'espionnage car vous pouvez simplement vous moquer de DepositMoneyService et de WithdrawMoneyService.

Mais avec certains codes hérités, 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 modifier le premier code mais l’API est modifiée. Si cette méthode est utilisée par de nombreux endroits, vous devez tous les changer.

Alternative est que vous pouvez extraire 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 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.

11

Version TL; DR,

Avec mock , il crée pour vous une instance Shell nue.

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

Avec spy vous pouvez vous moquer partiellement d'un existant instance

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

Cas d'utilisation typique de Spy: la classe a un constructeur paramétré, vous voulez d'abord créer l'objet.

9
del bao

Le meilleur endroit pour commencer est probablement la documentation pour mockito .

Sur une note générale, le mockito mockito vous permet de créer des talons. 

Vous créez une méthode de remplacement si, par exemple, cette méthode effectue une opération coûteuse. Disons qu'il obtient une connexion à la base de données, récupère une valeur de la base de données et la renvoie à l'appelant. L'obtention de la connexion à la base de données peut prendre 30 secondes, ce qui ralentit l'exécution du test au point où vous pourrez probablement changer de contexte (ou arrêter l'exécution du test). 

Si la logique que vous testez ne se soucie pas de la connexion à la base de données, vous pouvez remplacer cette méthode par un stub qui renvoie une valeur codée en dur.

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 de tester le code existant.

Il est utile si vous testez une méthode qui fonctionne avec des effets secondaires, alors vous utiliseriez un espion mockito. Cela délègue les appels à l'objet réel et vous permet de vérifier l'appel de la méthode, le nombre de fois invoqué, etc.

9
Jaimie Whiteside

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 totalement fictif ou fictif alors que vous êtes en mode espion, il existe un objet réel et vous ne faites que l'espionner ou le remplacer par des méthodes spécifiques.

Bien qu’il s’agisse d’objets espions, bien sûr, étant donné qu’il s’agit d’une méthode réelle, elle appelle le comportement de la méthode réelle lorsque vous ne la remplacez pas. Si vous voulez changer et simuler la méthode, alors vous devez la stub.

Considérons l'exemple ci-dessous à titre de 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 devrais-tu te moquer ou espionner? Si vous voulez être en sécurité 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 souhaitez appeler un service externe et effectuer un appel de dépendance réelle, ou simplement dire, vous souhaitez exécuter le programme tel quel et simplement utiliser des méthodes spécifiques au stub, utilisez espion. C’est donc la différence entre espion et simulacre de mockito.

8
Vu Truong

J'aime la simplicité de cette recommandation:

  • Si vous voulez être en sécurité 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 souhaitez appeler un service externe et effectuer l'appel de dépendances réelles, ou simplement dire, vous souhaitez exécuter le programme tel quel et simplement utiliser des méthodes spécifiques au stub, utilisez spy.

Source: https://javapointers.com/tutorial/difference-between-spy-and-mock-in-mockito/

1
leo9r

Vous pouvez suivre l'URL du blog ci-dessous, où il est comparé aux points ci-dessous:

  1. Déclaration d'objet
  2. Quand on ne se moque pas des méthodes
  3. Quand la méthode est moquée

https://onlyfullstack.blogspot.com/2019/02/mockito- mock-vs-spy.html URL principale du tutoriel - https://onlyfullstack.blogspot.com/2019/02/mockito-tutorial .html

0
Saurabh Oza