2010-11-22 25 views
3

J'ai un problème avec Mockito.Tests unitaires avec mockito (moquerie partielle)

Est-il possible de faire une telle chose:

ClassX x = mock(ClassX.class) 
when(x.methodB()).thenReturn("toto"); 
String result = x.methodA(); 

Je travaille avec Mockito 1.7.

j'ai vu qu'il y avait un système « d'espionnage », mais ils disent qu'il est recommandé de ne pas l'utiliser (pourquoi?) Sur la question que nous testons ...

J'ai essayé cette fonction d'espionnage de toute façon, mais je reçois un comportement étrange .

Vérifiez ce que je veux faire:

Code réel:

String methodA(String arg) { 
    return this.methodB(arg); 
} 

String methodB(String arg) { 
    return "toto"; 
} 

Code d'essai:

@Test 
public void testTest() { 
    final ClassX x = spy(new ClassX()); 
    final String argument = "arg"; 
    doReturn("good").when(helper).methodB(argument); 
    assertTrue( x.methodB(argument).equals("good")); 
    assertTrue( x.methodA(argument).equals("good")); 
} 

Comme ils ont dit que j'évitais la quand une syntaxe thenReturn qui pourrait être un problème un espion (mais ça ne marche pas non plus de toute façon)

La chose étrange est que: assertTrue (x.methodB (argument) .equals ("bon")); est OK

Seul le second assertTrue (x.methodA (argument) .equals ("good")); n'est pas OK

En fait helper.methodA (argument) retourne « toto » -> le résultat réel et non le résultat simulé

Il est impossible de dire Mockito revenir « bon » dans ce cas? ?? Il semble que lorsque la classe de test appelle la méthodeB c'est ok, mais si une méthode de l'espion appelle la méthodeB cela ne marche plus ...

Je ne sais pas quoi faire ... est-ce si étrange chose à l'unité-tester 2 méthodes de la même classe et de rendre les tests indépendants les uns des autres de sorte qu'un célèbre cadre de test de simulation ne met pas en œuvre cette fonction de base? N'est-ce pas ce que nous appelons de vrais tests unitaires? Je ne comprends pas pourquoi ils disent d'éviter d'utiliser la méthode d'espionnage sur l'objet testé ...

Merci

+0

Juste essayé avec Mockito 1.9.5 et tous les deux ont renvoyé '' bon ''. Donc je suppose que ce comportement est parti. – acdcjunior

Répondre

2

L'espion est un objet différent de l'objet espionné. L'espion ne délègue que vers l'objet espionné. Ainsi, lorsque l'objet spié appelle methodB de methodA, il l'appelle sur lui-même, pas sur l'espion.

+0

Merci :) mais avez-vous une solution pour faire ce que je veux? –

+0

Je suppose que je pourrais utiliser une classe réelle anonyme et redéfinir MethodB, mais mockito ne donne pas un vrai pour cette solution? –

+0

Mettez à la place 'methodB' sur un autre objet que vous fournissez en tant que dépendance pour l'objet qui a' methodA', par exemple en tant que paramètre constructeur. De cette façon, vous pouvez simuler l'objet 'methodB'. Si vous donnez les noms propres de vos objets et méthodes, je peux vous suggérer de meilleurs noms. –

4

MISE À JOUR: J'ai écrit les choses ci-dessous, puis quelques instants plus tard découvert .thenCallRealMethod() qui vous permet d'effectuer efficacement partiellement talonnage. Les auteurs de Mockito vous recommandent d'utiliser le refactoring pour séparer les dépendances en différentes classes; mais ils fournissent les moyens de talonner partiellement. J'ai ajouté une méthode de test pour démontrer cette approche, et laisser mes commentaires originaux. J'aime beaucoup Mockito, mais c'est le seul endroit où EasyMock l'emporte. J'ai deux solutions pour vous qui n'impliquent pas Mockito. La première consiste à remplacer la méthode B sur votre instance de test. L'autre consiste à simuler partiellement avec EasyMock:

import org.junit.Test; 
import static org.junit.Assert.*; 
import static org.easymock.EasyMock.*; 

public class PartialMockTest { 

    class ClassX { 
     String methodA(String arg) {return methodB(arg);} 
     String methodB(String arg) {return "toto";} 
    } 

    @Test 
    public void MockitoOnClassX(){ 
     ClassX classx = mock(ClassX.class); 
     when(classx.methodB("hiyas")).thenReturn("tomtom"); 
     when(classx.methodA(anyString())).thenCallRealMethod(); 
     String response = classx.methodA("hiyas"); 
     assertEquals("tomtom",response); 
    } 


    @Test 
    public void OverrideOnClassX() { 
     ClassX classx = new ClassX(){@Override String methodB(String arg){return "tomtom";}}; 
     String response = classx.methodA("hiyas"); 
     assertEquals("tomtom",response); 
    } 

    @Test 
    public void PartialMockOnClassX() throws NoSuchMethodException { 
     ClassX classx = createMockBuilder(ClassX.class).addMockedMethod("methodB").createMock(); 
     expect(classx.methodA("hiyas")).andReturn("tomtom"); 
     replay(classx); 
     String response = classx.methodA("hiyas"); 
     assertEquals("tomtom",response); 
    } 

}