2013-02-19 3 views
1

Voici ma hiérarchie de classesJUnit Test: l'invocation classe parente Méthode protégée

abstract Class A 
{ 
    int i = 0; 
    protected init (String param1, String param2) 
    { 
     //do lots of common things based on param1, param2 and save data in i 
    } 
} 

Ensuite, il y a 3-4 classes qui implémente A par exemple

Class B extends A 
{ 
    public B() 
    { 
     super(); 
    } 

    public void performSomeAction() 
    { 
     init (param1_specific_to_class_B, param2_specific_to_class_B); //calling parent class method 
     //do rest of teh random things 
    } 
} 

Maintenant, je suis en train d'écrire un JUnit test pour la classe A. Fondamentalement, je veux tester tout ce que la méthode fait est exacte ou non. J'ai essayé

Class clas = A.class; 
B b = new B(); 

Method A_init; 
A_init = clas.getDeclaredMethod("init", String.class, String.class); 
A_init.invoke(b, param1_specific_to_class_B, param2_specific_to_class_B); 

Mais sa ne fonctionne pas et je reçois exception suivante

java.lang.IllegalAccessException: Class test.package.subpackage.ATest can not access a member of class package.subpackage.A with modifiers "protected" 
    at sun.reflect.Reflection.ensureMemberAccess(Reflection.java:65) 
    at java.lang.reflect.Method.invoke(Method.java:578) 
    at test.package.subpackage.ATest.initTest(ATest.java:49) 
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) 
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) 
    at java.lang.reflect.Method.invoke(Method.java:585) 

Répondre

4

Vous pouvez placer votre classe de test dans le même package que la classe testée. Ainsi, la classe de test aura accès à la méthode protégée.

Une autre option, un peu plus élégante, est de rendre la méthode protégée accessible:

A_init = clas.getDeclaredMethod("init", String.class, String.class); 
A_init.setAccessible(true); 
A_init.invoke(b, param1_specific_to_class_B, param2_specific_to_class_B); 

Hope it helps.

+0

Le déplacement de la classe vers ce paquet n'est pas une option puisque nous avons deux hiérarchies de paquetages différentes (les classes de projet étant dans le dossier src et le test étant dans le test foldeR). merci pour le 'setAccessible (true)'.C'est ce que je recherchais –

+0

Comme cela arrive avec les projets Maven, vous avez un src et un dossier de test, mais différents dossiers ne signifient pas nécessairement des paquets différents. – Lucas

1

protected membres d'une classe ne sont pas visible à une classe d'un autre paquet à moins qu'il est une sous-classe de l'ancien.

Toutefois, dans votre application, la classe test.package.subpackage.ATest tente d'accéder à une méthode protégée d'une autre classe dans package.subpackage, ce qui entraîne la violation d'accès.

Essayez de placer la classe ATest dans un emplacement tel que A et ATest appartiennent au même package.

0

Peut-être que je manque quelque chose, mais, puisque B est ne surchargez pas A.init() (au moins, de ce que je peux voir), vous pouvez juste aller

B b = new B() 
b.init(param1_specific_to_class_B, param2_specific_to_class_B) 

Si B est prépondérant init (),

  1. tout mettre dans le même paquet (comme d'autres ont posté)
  2. en cas de changement des paquets est impossible ou désiré, vous devrez peut-être ajouter une méthode spéciale pour B qui appelle super.init(). Je dirais quelque chose comme callSuperInitForUnitTests() et préciser dans les commentaires que c'est une solution de contournement pour les tests unitaires.
+0

désolé c'était une faute de frappe. B étend A. J'ai corrigé le code –

+0

Je savais que B étendait A. Le fait est que si vous voulez tester A.init, et que B ne surcharge pas A.init, vous pouvez simplement appeler b.init(). Dans le cas contraire, voici quelques solutions de contournement possibles: déplacez les fichiers dans le même package, définissez access, ou appelez A.init via un intermédiaire. – user949300

1

Alternativement dans votre TestClass créer une sous-classe A et exposer la méthode protégée (s) par une méthode publique:

public class TestClass extends TestCase(){ 

    // ... 

    private class AChild extends A{ 
     public exposeInit (String param1, String param2){ 
     super.init(param1, param2); 
     } 
    } 
} 

maintenant vous pouvez tester init classe A en testant init unenfant de classe.

J'ai eu un problème similaire, mais nous l'avons résolu en changeant le design en composition au lieu de l'héritage.