L'emballage d'un code tiers est-il la seule solution pour tester unitairement ses consommateurs?

13

Je fais des tests unitaires et dans l'une de mes classes, je dois envoyer un courrier à partir d'une des méthodes, donc en utilisant l'injection de constructeur j'injecte une instance de Zend_Mailclasse qui est dans le framework Zend.

Maintenant, certaines personnes soutiennent que si une bibliothèque est suffisamment stable et ne change pas souvent, il n'est pas nécessaire de la boucler. Donc, en supposant que cela Zend_Mailsoit stable et ne changera pas et qu'il correspond entièrement à mes besoins, je n'aurai pas besoin d'un wrapper pour cela.

Jetez maintenant un œil à ma classe Loggerqui dépend de Zend_Mail:

class Logger{
    private $mailer;    
    function __construct(Zend_Mail $mail){
        $this->mail=$mail;
    }    
   function toBeTestedFunction(){
      //Some code
      $this->mail->setTo('some value');
      $this->mail->setSubject('some value');
      $this->mail->setBody('some value');
      $this->mail->send();
     //Some
   }        
}

Cependant, les tests unitaires exigent que je teste un composant à la fois, donc je dois me moquer de la Zend_Mailclasse. De plus, je viole le principe de l' inversion de dépendance car ma Loggerclasse dépend maintenant de la concrétion et non de l'abstraction.

Maintenant, comment puis-je tester Loggerde manière isolée sans envelopper Zend_Mail?!

Le code est en PHP, mais les réponses ne doivent pas nécessairement l'être. Il s'agit plus d'un problème de conception que d'une fonctionnalité spécifique à une langue

Songo
la source
Devez-vous utiliser une interface? PHP ne prend-il pas en charge la saisie de canards?
kevin cline
@kevincline j'ai bien utilisé PHP car c'est le langage que j'utilise le plus, mais je cherche en fait une solution générale au problème qui ne se limite pas à PHP uniquement.
Songo

Réponses:

21

Vous voulez toujours envelopper les types et méthodes tiers derrière une interface. Cela peut être fastidieux et douloureux. Parfois, vous pouvez écrire un générateur de code ou utiliser un outil pour ce faire.

Mais ne soyez pas tenté d'utiliser les méthodes ou types de bibliothèque dans votre code. Pour commencer, vous aurez du mal à écrire des tests unitaires. Ensuite, une licence changera, ou vous voudrez aller sur une plate-forme non prise en charge par le tiers, et vous constaterez que ces types et dépendances se sont tissés dans et autour de toutes vos autres classes.

La possibilité de changer rapidement de fournisseurs tiers est un énorme avantage.

Ben
la source
4
"Tout ce que vous n'avez pas écrit" est un peu trop. Les bibliothèques qui font partie de la norme ou de la plate-forme sont difficiles à encapsuler. Vous ne voudriez probablement pas envelopper tous les composants .NET, par exemple. Si les wrappers passent simplement par des interfaces, ou sont générés par du code, j'ai trouvé peu d'avantages à écrire des tests. S'il y a de la logique (combinaison d'appels, etc.), les tests peuvent être utiles.
Ben
3
A voté pour la dernière phrase.
Blrfl
1
Si vous refactorisez correctement, toute utilisation répétitive des installations de la bibliothèque sera prise en compte dans une classe de service. Pas besoin de le définir d'avance.
kevin cline
3
-1: Sauf dans les cas où la bibliothèque tierce fournit un service pour lequel il existe une API standardisée, c'est une énorme perte de temps et ne réduira la maintenabilité qu'en vous faisant dupliquer du code. Aussi, YAGNI.
Michael Borgwardt
1
@MichaelBorgwardt: Bien sûr, mais dans ce cas, l'API standard devient l'encapsuleur et vous pouvez facilement échanger des bibliothèques.
Blrfl