2015-12-31 3 views
0

Le contrôleur utilise request.getParameter à l'avant, le code comme ci-dessousComment puis-je utiliser Mockito pour tester uniquement l'avant?

public class ComputingController extends HttpServlet { 

    public ComputingController() { 
     super(); 
    } 

    public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { 

     String reDirect = request.getParameter("redirect"); 
     RequestDispatcher rd = null; 

     if ("update".equals(reDirect)) { 

      UpdateData updateData = new UpdateData(); 
      String updateResult = updateData.doUpdateData(); 
      request.setAttribute("updateResult", updateResult); 

      rd = request.getRequestDispatcher("WEB-INF/jsp/computing/success.jsp"); 
      rd.forward(request, response); 
     } 
     else { 

      rd = request.getRequestDispatcher("WEB-INF/jsp/computing/error.jsp"); 
      rd.forward(request, response); 
     } 
    } 

} 

J'utilise Junit et Mockito pour tester en avant.

Mais quand j'exécuterai le test (comme ci-dessous), il exécutera updateData.doUpdateData() dans le contrôleur.

Comment puis-je utiliser le Mockito pour qu'il n'exécute pas updateData.doUpdateData() mais forward?

public class ComputingControllerTest { 

    @Mock 
    HttpServletRequest request; 

    @Mock 
    HttpServletResponse response; 

    @Mock 
    RequestDispatcher rd; 

    @Before 
    public void setUp() throws Exception { 
     MockitoAnnotations.initMocks(this); 
    } 

    public void doGet_testForward() throws Exception { 

     String reDirect = "update"; 

     when(request.getParameter("redirect")).thenReturn(reDirect); 

     when(request.getRequestDispatcher("WEB-INF/jsp/computing/success.jsp")).thenReturn(rd); 

     new ComputingController().doGet(request, response); 

     verify(rd).forward(request, response); 

    } 
} 
+0

En l'état, vous ne pouvez pas. Pour être en mesure de le faire, vous devez fournir une mise à jour UpdateData à la servlet, et la servlet devrait utiliser cette fausse UpdateData, au lieu de créer sa propre nouvelle à chaque fois. C'est essentiellement le principe de l'injection de dépendance. –

Répondre

1

Votre problème est ...

UpdateData updateData = new UpdateData(); 
String updateResult = updateData.doUpdateData(); 
request.setAttribute("updateResult", updateResult); 

Vous ne pouvez pas vraiment sauter complètement et avec seulement la modification de votre test, vous ne serez pas loin. Donc, ce dont vous avez besoin, c'est d'un moyen d'injecter un autre UpdateData() là-dedans (que vous pouvez alors simuler). Une possibilité serait, par exemple, un modèle d'usine ...

private UpdateDataFactory factory; 

public ComputingController(UpdateDataFactory factory) { 
    super(); 
    this.factory = factory; 
} 

public ComputingController() { 
    super(new DefaultUpdataDataFactory()); // simply creates a new UpdateData(); 
    this.factory = factory; 
} 

Maintenant, vous pouvez écrire à la place ...

UpdateData updateData = this.factory.createUpdataData(); 

Et dans votre test, vous pouvez railler l'usine et l'insérer. ..

@Mock 
private UpdateDataFactory factory; 

@Mock 
private UpdateData data; 

... 

when(factory.createUpdataData()).thenReturn (data); 
new ComputingController(factory).doGet(request, response); 

maintenant, l'appel à doUpdataData() sera rien, car il ne fait que la maquette, mais vous pouvez le vérifier

Oh, et vous pouvez faire la création du ComputingController (et l'injection de la maquette) automatiquement via @InjectMocks ...

@InjectMocks 
private ComputingController controller; 
+0

Merci pour votre aide. c'est utile pour moi ~ – Gene

1

Ce ne est pas possible d'y parvenir sans modifier le code source existant de ComputingController classe.

Si vous êtes ouvert à modifier ComputingController, ci-dessous est ce que vous pouvez faire pour appel simulé - updateData.doUpdateData(),

  1. Créer une méthode getUpdateData() en ComputingController par défaut ou protected accessibilité de niveau (private ne fonctionnera pas et public est pas conseillé),

UpdateData getUpdateData() {return new UpdateData();}

  1. Remplacer la ligne new UpdateData(); avec getUpdateData() dans ComputingController
  2. Créer une classe non publique ComputingControllerTestable dans public class ComputingControllerTest

class ComputingControllerTestable extends ComputingController { private UpdateData updateData; @Override protected void getUpdateData(){return updateData;} protected void setUpdateData(UpdateData updateData){this.updateData=updateData;} }

  1. Maintenant, dans votre classe de test, remplacer votre classe-sous-test type à ComputingControllerTestable au lieu de ComputingController

  2. Dans votre ComputingControllerTest, déclare un champ moqué, @Mock private UpdateData updateData;

  3. maintenant dans votre méthode @Before de classe de test, méthode setter appel du ComputingControllerTestable pour le champ moqués de classe de test, testObj.setUpdateData(updateData);testObj est classe sous test objet créé à l'étape n ° 4.

Je suppose que vos classes de test et de classe sont dans le même paquet.

moyen facile (pour éviter tout six étapes ci-dessus) est de déclarer UpdateData objet en tant que dépendance (champ d'instance) dans ComputingController classe au lieu de créer une nouvelle UpdateData à chaque fois à l'intérieur de doGet procédé et railler que la dépendance en ComputingControllerTest

J'espère que cela aide !!