J'ai trouvé la discussion sur Do you test private method informative.
J'ai décidé que, dans certaines classes, je veux avoir des méthodes protégées, mais testez-les. Certaines de ces méthodes sont statiques et courtes. Étant donné que la plupart des méthodes publiques les utilisent, je pourrai probablement supprimer les tests en toute sécurité plus tard. Mais pour commencer avec une approche TDD et éviter le débogage, je veux vraiment les tester.
J'ai pensé à ce qui suit:
- Objet de méthode comme conseillé dans une réponse semble être exagéré pour cela.
- Commencez avec des méthodes publiques et lorsque la couverture de code est donnée par des tests de niveau supérieur, protégez-les et supprimez les tests.
- Hériter d'une classe avec une interface testable rendant les méthodes protégées publiques
Quelle est la meilleure pratique? Y a-t-il autre chose?
Il semble que JUnit change automatiquement les méthodes protégées pour qu'elles soient publiques, mais je ne l'ai pas approfondi. PHP ne permet pas cela via la réflexion .
php
unit-testing
phpunit
GrGr
la source
la source
Réponses:
Si vous utilisez PHP5 (> = 5.3.2) avec PHPUnit, vous pouvez tester vos méthodes privées et protégées en utilisant la réflexion pour les définir comme publiques avant d'exécuter vos tests:
la source
protected
méthode fait également partie de l'API publique car toute classe tierce peut l'étendre et l'utiliser sans magie. Je pense donc que seules lesprivate
méthodes entrent dans la catégorie des méthodes à ne pas tester directement.protected
etpublic
doit être testé directement.Vous semblez déjà au courant, mais je vais tout de même le répéter; C'est un mauvais signe, si vous devez tester des méthodes protégées. Le but d'un test unitaire est de tester l'interface d'une classe et les méthodes protégées sont des détails d'implémentation. Cela dit, il y a des cas où cela a du sens. Si vous utilisez l'héritage, vous pouvez voir une superclasse comme fournissant une interface pour la sous-classe. Donc, ici, vous devrez tester la méthode protégée (mais jamais une méthode privée ). La solution à cela consiste à créer une sous-classe à des fins de test et à l'utiliser pour exposer les méthodes. Par exemple.:
Notez que vous pouvez toujours remplacer l'héritage par la composition. Lors du test de code, il est généralement beaucoup plus facile de gérer le code qui utilise ce modèle, vous pouvez donc envisager cette option.
la source
teastburn a la bonne approche. Encore plus simple est d'appeler directement la méthode et de renvoyer la réponse:
Vous pouvez l'appeler simplement dans vos tests en:
la source
Je voudrais proposer une légère variation à getMethod () définie dans la réponse d'uckelman .
Cette version change getMethod () en supprimant les valeurs codées en dur et en simplifiant un peu l'utilisation. Je recommande de l'ajouter à votre classe PHPUnitUtil comme dans l'exemple ci-dessous ou à votre classe d'extension PHPUnit_Framework_TestCase (ou, je suppose, globalement à votre fichier PHPUnitUtil).
Puisque MyClass est de toute façon instancié et ReflectionClass peut prendre une chaîne ou un objet ...
J'ai également créé une fonction d'alias getProtectedMethod () pour être explicite sur ce qui est attendu, mais c'est à vous de décider.
À votre santé!
la source
Je pense que troelskn est proche. Je ferais cela à la place:
Ensuite, implémentez quelque chose comme ceci:
Vous exécutez ensuite vos tests par rapport à TestClassToTest.
Il devrait être possible de générer automatiquement de telles classes d'extension en analysant le code. Je ne serais pas surpris si PHPUnit propose déjà un tel mécanisme (même si je n'ai pas vérifié).
la source
Je vais jeter mon chapeau dans le ring ici:
J'ai utilisé le hack __call avec des degrés de réussite mitigés. L'alternative que j'ai trouvée était d'utiliser le modèle Visitor:
1: générer une classe stdClass ou personnalisée (pour appliquer le type)
2: amorcez cela avec la méthode et les arguments requis
3: assurez-vous que votre SUT a une méthode acceptVisitor qui exécutera la méthode avec les arguments spécifiés dans la classe visiteuse
4: injectez-le dans la classe que vous souhaitez tester
5: SUT injecte le résultat de l'opération au visiteur
6: appliquez vos conditions de test à l'attribut de résultat du visiteur
la source
Vous pouvez en effet utiliser __call () de manière générique pour accéder aux méthodes protégées. Pour pouvoir tester cette classe
vous créez une sous-classe dans ExampleTest.php:
Notez que la méthode __call () ne référence en aucune façon la classe, vous pouvez donc copier ce qui précède pour chaque classe avec les méthodes protégées que vous souhaitez tester et simplement modifier la déclaration de classe. Vous pourrez peut-être placer cette fonction dans une classe de base commune, mais je ne l'ai pas essayée.
Maintenant, le cas de test lui-même ne diffère que par l'endroit où vous construisez l'objet à tester, en échangeant dans ExampleExposed for Example.
Je crois que PHP 5.3 vous permet d'utiliser la réflexion pour modifier directement l'accessibilité des méthodes, mais je suppose que vous devrez le faire pour chaque méthode individuellement.
la source
call_user_method_array()
fonction est obsolète à partir de PHP 4.1.0 ... utilisezcall_user_func_array(array($this, $method), $args)
plutôt. Notez que si vous utilisez PHP 5.3.2+, vous pouvez utiliser Reflection pour accéder aux méthodes et attributs protégés / privésAccessible
package générique qui utilise la réflexion pour permettre aux tests d'accéder aux propriétés et méthodes privées / protégées des classes et des objets.__call()
n'est invoqué que si l'appelant n'a pas accès à la méthode. Puisque la classe et ses sous-classes ont accès aux méthodes protégées, les appels à celles-ci ne passeront pas__call()
. Pouvez-vous publier votre code qui ne fonctionne pas dans 5.2.7 dans une nouvelle question? J'ai utilisé ce qui précède dans 5.2 et je suis passé à l'utilisation de la réflexion avec 5.3.2.Je suggère la solution de contournement suivante pour la solution / idée de "Henrik Paul" :)
Vous connaissez les noms des méthodes privées de votre classe. Par exemple, ils sont comme _add (), _edit (), _delete () etc.
Par conséquent, lorsque vous voulez le tester sous l'aspect des tests unitaires, il suffit d'appeler des méthodes privées en préfixant et / ou en suffixant un mot commun (par exemple _addPhpunit) de sorte que lorsque la méthode __call () est appelée (puisque la méthode _addPhpunit () ne le fait pas existe) de la classe propriétaire, vous venez de mettre le code nécessaire dans la méthode __call () pour supprimer les mots / s préfixés / suffixés (Phpunit), puis pour appeler cette méthode privée déduite à partir de là. Ceci est une autre bonne utilisation des méthodes magiques.
Essaye le.
la source