2017-08-02 23 views
-2

Ma question est de savoir comment utiliser la méthode doAnswer de Mockito pour appeler la méthode d'origine et avec mes propres paramètres de test. Pour compliquer les choses, l'un des paramètres n'est pas une primitive. C'est une classe personnalisée.Comment se moquer d'une méthode setter en utilisant Mockito avec plusieurs paramètres

Compte tenu de ce qui suit:

public class EnvironmentQualityStatus { 
    public int environmentQuality = EnvironmentQualityStatus.NA; 
    public long cht = -1; 
    public int environmentSubType = -1; 
    public String engineer=""; 
    public int engineerType = -1; 
    public long timeStamp = 0; 
    public static final String version = "tpv1"; 

    EnvironmentQualityStatus(){} 

    EnvironmentQualityStatus(int environmentQuality, long cht, int environmentSubType, String engineer, int engineerType) { 
     this.environmentQuality = environmentQuality; 
     this.cht = cht; 
     this.environmentSubType = environmentSubType; 
     this.engineer = engineer; 
     this.engineerType = engineerType; 
     timeStamp = System.currentTimeMillis(); 
    } 

    @Override 
    public String toString() { 
     StringBuilder sb = new StringBuilder(); 
     sb.append("ts: "); 
     sb.append(timeStamp); 
     sb.append(", quality: "); 
     sb.append(EnvironmentQualityStatus.valueOf(environmentQuality)); 
     sb.append(", cht: "); 
     sb.append(cht); 
     sb.append(", type: "); 
     if (engineerType == Engineers.TYPE_CIVIL) { 
      sb.append(“civil”); 
     } else if (engineerType == Engineers.TYPE_INDUSTRIAL) { 
      sb.append(“industrial”); 
      if (!TextUtils.isEmpty(engineer)) { 
       sb.append(", Engineer: "); 
       sb.append(engineer); 
      } 
     } else { 
      sb.append("n/a"); 
     } 
     return sb.toString(); 
    } 
} 

Prise en utilisant ce code ci-dessus pour définir des choses dans une classe. C'est cet appel (et d'autres comme celui-ci) que j'aimerais faire en utilisant Mockito. Je comprends que l'utilisation de doAnswer de Mockito est la bonne façon de le faire. Je n'arrive pas à comprendre comment câbler la toute dernière partie, où je manipule les valeurs appelées avec les miennes pour que le programme qui les utilise au moment de l'exécution du test obtienne mes valeurs. J'ai lu des documents Mockito ainsi que plusieurs publications sur ce sujet, mais ce n'est toujours pas clair pour moi.

EnvironmentQuality environmentQuality = spy((EnvironmentQuality)EnvironmentQuality.getInstance(context)); 

    spy(environmentQuality).updateNetworkQuality(Mockito.any(com.something.internal.EnvironmentQualityStatus.class), anyInt(), anyInt(), anyString(), anyBoolean()); 
    doAnswer(new Answer<Void>() { 
     @Override 
     public Void answer(InvocationOnMock invocation) throws Throwable { 

      //This is an example of how to spy the parameters that were passed. 
      EnvironmentQualityStatus status = (EnvironmentQualityStatus)invocation.getArguments()[0]; 

      int environmentQuality = (int)invocation.getArguments()[1]; 
      int cht = (int)invocation.getArguments()[2]; 
      String engineer = (String)invocation.getArguments()[3]; 
      boolean notify = (boolean)invocation.getArguments()[4]; 

      //But how to customize the parameters so that every time updateEnvironmentQuality(...) is called, a test can customize the params and dynamically influence the values. 
      return null; 
     } 
    }).when(environmentQuality).updateEnvironmentQuality(Mockito.any(com.something.internal.EnvironmentQualityStatus.class), anyInt(), anyInt(), anyString(), anyBoolean()); 
+1

Vous pouvez mettre à jour le paramètre EnvironmentQualityStatus uniquement dans le doAnswer, car le reste est immuable. –

+1

Pourquoi le -1? Je pense que la question et votre réponse pourraient clarifier la même chose à quelqu'un d'autre. –

+1

Votre question n'est pas claire pour moi. Voulez-vous dire que vous voulez aussi appeler la vraie version de la méthode stubbed, mais avec des valeurs modifiées pour les paramètres? Je ne crois pas que Mockito le fasse actuellement, mais vous pourriez faire une demande de fonctionnalité. –

Répondre

1

Je suppose donc que vous voulez appeler la méthode avec d'autres valeurs. En vérifiant the documentation de InvocationOnMock vous pouvez vérifier comment obtenir le Method et le Object qui s'appelle. Donc, cela devrait être assez facile à modifier:

@Override 
    public Void answer(InvocationOnMock invocation) throws Throwable { 
     Object callingObject = invocation.getMock(); 
     Method method = invocation.getMethod(); 
     method.invoke(callingObject, /* arguments... */); 
     return null; 
    } 
+0

Je voudrais ajouter à cela. Dans le cas où vous essayez d'utiliser la méthode par procuration (comme je le fais), nous nous retrouvions dans une situation d'appel récursif. Lorsque nous appelons la méthode avec nos propres paramètres, nous revenons dans la réponse. Donc, la solution consiste à utiliser la réflexion pour obtenir les variables membres définies par la méthode setter. Par conséquent, le résultat (pour nous) est le même sans le problème de la récursivité. Votre kilométrage peut varier. –

+0

Avez-vous testé cela? Je ne suis pas sûr que ça va marcher. Selon le Javadoc pour la méthode 'invoke' de' Method', _ "... il est appelé en utilisant la méthode dynamique de recherche comme documenté dans la spécification du langage Java, deuxième édition, section 15.12.4.4, en particulier, le remplacement basé sur le le type d'exécution de l'objet cible se produira ... "_ Cela signifie que vous appelez à nouveau la méthode sur l'objet stubbed. Ainsi, votre méthode 'answer' s'appellera à plusieurs reprises jusqu'à ce que votre pile déborde. –