web-dev-qa-db-fra.com

Test de la méthode privée en utilisant mockito

 public class A {

 méthode vide publique (booléen b) {
 si (b == vrai) 
 method1 (); 
 autre
 method2 (); 
 } 

 private void method1 () {} 
 private void method2 () {} 
} 
 public class TestA {

 @Tester
 public void testMethod () {
 A a = mock (A.class); 
 a.method (true); 
 // comment tester comme verify (a) .method1 (); 
 } 
} 

Comment tester la méthode privée s'appelle ou non, et comment tester la méthode privée en utilisant mockito ???

78
Nageswaran

Vous ne pouvez pas faire cela avec Mockito mais vous pouvez utiliser Powermock pour étendre Mockito et se moquer des méthodes privées. Powermock soutient Mockito. Ici est un exemple.

64
shift66

Pas possible à travers mockito. De leur wiki

Pourquoi Mockito ne se moque pas des méthodes privées?

Premièrement, nous ne sommes pas dogmatiques à propos de se moquer des méthodes privées. Nous venons ne vous souciez pas des méthodes privées parce que du point de vue de les tests de méthodes privées n'existent pas. Voici quelques raisons Mockito ne se moque pas des méthodes privées:

Cela nécessite un piratage des chargeurs de classe qui n’est jamais à l’abri des balles et cela change l'api (vous devez utiliser un testeur personnalisé, annoter la classe, , etc.). 

Il est très facile de contourner le problème - il suffit de changer la visibilité de la méthode de private à package-protected (ou protected). 

Cela me demande de passer du temps à le mettre en œuvre et à le maintenir. Et cela n'a pas de sens étant donné le point n ° 2 et un fait qu'il est déjà mis en œuvre dans un outil différent (powermock). 

Enfin ... Se moquer des méthodes privées est un indice qu'il y a quelque chose mal avec OO compréhension. Dans OO, vous souhaitez que les objets (ou les rôles) soient collaborer, pas des méthodes. Oubliez Pascal et le code de procédure. Pense dans les objets.

106
Aravind R. Yarram

Voici un petit exemple comment faire avec powermock

public class Hello {
    private Hello obj;
    private Integer method1(Long id) {
        return id + 10;
    }
} 

Pour tester method1, utilisez le code:

Hello testObj = new Hello();
Integer result = Whitebox.invokeMethod(testObj, "method1", new Long(10L));

Pour définir l'objet privé obj, utilisez ceci:

Hello testObj = new Hello();
Hello newObject = new Hello();
Whitebox.setInternalState(testObj, "obj", newObject);
22
Mindaugas Jaraminas

Pensez à cela en termes de comportement, pas en termes de méthodes. La méthode appelée method a un comportement particulier si b est vrai. Son comportement est différent si b est faux. Cela signifie que vous devriez écrire deux tests différents pour method; un pour chaque cas. Ainsi, au lieu d’avoir trois tests axés sur la méthode (un pour method, un pour method1, un pour method2, vous avez deux tests axés sur le comportement.

En rapport avec cela (je l'ai suggéré récemment dans un autre fil SO, et je me suis appelé un mot de quatre lettres en conséquence, alors n'hésitez pas à le prendre avec un grain de sel); Je trouve utile de choisir des noms de test qui reflètent le comportement que je teste, plutôt que le nom de la méthode. Donc, n'appelez pas vos tests testMethod(), testMethod1(), testMethod2() et ainsi de suite. J'aime les noms comme calculatedPriceIsBasePricePlusTax() ou taxIsExcludedWhenExcludeIsTrue() qui indiquent le comportement que je teste. Ensuite, dans chaque méthode de test, testez uniquement le comportement indiqué. La plupart de ces comportements impliquent un seul appel à une méthode publique, mais peuvent impliquer de nombreux appels à des méthodes privées.

J'espère que cela t'aides.

15
Dawood ibn Kareem

Vous n'êtes pas censé tester des méthodes privées. Seules les méthodes non privées doivent être testées, car elles doivent quand même appeler les méthodes privées. Si vous "voulez" tester des méthodes privées, cela peut indiquer que vous devez repenser votre conception:

Est-ce que j'utilise une injection de dépendance appropriée? ... ne peuvent-ils pas être protégés par défaut ou plutôt?

Dans l'exemple ci-dessus, les deux méthodes appelées "de manière aléatoire" peuvent en réalité devoir être placées dans une classe à part, testées puis injectées dans la classe ci-dessus.

5
Jaco Van Niekerk

J'ai pu tester une méthode privée à l'intérieur en utilisant mockito en utilisant la réflexion . Voici l'exemple, essayé de le nommer de manière à ce que cela ait un sens

//Service containing the mock method is injected with mockObjects

@InjectMocks
private ServiceContainingPrivateMethod serviceContainingPrivateMethod;

//Using reflection to change accessibility of the private method

Class<?>[] params = new Class<?>[]{PrivateMethodParameterOne.class, PrivateMethodParameterTwo.class};
    Method m = serviceContainingPrivateMethod .getClass().getDeclaredMethod("privateMethod", params);
    //making private method accessible
    m.setAccessible(true); 
    assertNotNull(m.invoke(serviceContainingPrivateMethod, privateMethodParameterOne, privateMethodParameterTwo).equals(null));
4
Abdullah Choudhury

Je ne comprends pas vraiment votre besoin de tester la méthode privée. Le problème fondamental est que votre méthode publique a la valeur null comme type de retour et vous ne pouvez donc pas tester votre méthode publique. Par conséquent, vous êtes obligé de tester votre méthode privée. Est-ce que ma supposition est correcte?

Quelques solutions possibles (autant que je sache):

  1. Vous vous moquez de vos méthodes privées, mais vous ne pourrez toujours pas "réellement" tester vos méthodes. 

  2. Vérifiez l'état de l'objet utilisé dans la méthode. Les méthodes MOSTLY effectuent un traitement des valeurs d'entrée et renvoient une sortie, ou modifient l'état des objets. Le test des objets pour l’état souhaité peut également être utilisé. 

    public class A{
    
    SomeClass classObj = null;
    
    public void publicMethod(){
       privateMethod();
    }
    
    private void privateMethod(){
         classObj = new SomeClass();
    }
    
    }
    

    [Ici, vous pouvez tester la méthode privée, en vérifiant le changement d'état de classObj de null à non null.]

  3. Refacturez un peu votre code (j'espère que ce n'est pas un code hérité). Mon fond d'écriture d'une méthode est que, on devrait toujours renvoyer quelque chose (un int/a boolean). La valeur renvoyée PEUT ou NE PEUT PAS être utilisée par l’implémentation, mais elle sera SÛREMENT utilisée par le test. 

    code.

    public class A
    { 
        public int method(boolean b)
        {
              int nReturn = 0;
              if (b == true)
                   nReturn = method1();
              else
                   nReturn = method2();
        }
    
        private int method1() {}
    
        private int method2() {}
    
    }
    
2
Reji

Bien que Mockito ne propose pas cette fonctionnalité, vous pouvez obtenir le même résultat en utilisant Mockito + la classe JUnit ReflectionUtils ou la classe Spring ReflectionTestUtils . Veuillez voir un exemple ci-dessous tiré de ici expliquant comment appeler une méthode privée:

ReflectionTestUtils.invokeMethod(student, "saveOrUpdate", "From Unit test");

Vous trouverez des exemples complets avec ReflectionTestUtils et Mockito dans le livre Mockito for Spring

2
AR1

Placez votre test dans le même package, mais dans un dossier source différent (src/main/Java contre src/test/Java) et rendez ces méthodes package-private. La testabilité immédiate est plus importante que la vie privée.

1
Roland Schneider

Il existe actuellement un moyen de tester les méthodes d'un membre privé avec Mockito. Disons que vous avez un cours comme celui-ci:

public class A {
    private SomeOtherClass someOtherClass;
    A() {
        someOtherClass = new SomeOtherClass();
    }
    public void method(boolean b){
        if (b == true)
            someOtherClass.method1();
        else
            someOtherClass.method2();
    }

}

public class SomeOtherClass {
    public void method1() {}
    public void method2() {}
}

Si vous voulez tester a.method invoquerez une méthode de SomeOtherClass, vous pouvez écrire quelque chose comme ci-dessous.

@Test
public void testPrivateMemberMethodCalled() {
    A a = new A();
    SomeOtherClass someOtherClass = Mockito.spy(new SomeOtherClass());
    ReflectionTestUtils.setField( a, "someOtherClass", someOtherClass);
    a.method( true );

    Mockito.verify( someOtherClass, Mockito.times( 1 ) ).method1();
}

ReflectionTestUtils.setField(); bloque le membre privé avec quelque chose que vous pouvez espionner.

0
Fan Jin