¿Es envolver un código de terceros la única solución para probar a sus consumidores?

13

Estoy haciendo pruebas unitarias y en una de mis clases necesito enviar un correo desde uno de los métodos, así que usando la inyección del constructor, inyecto una instancia de Zend_Mailclase que está en el marco Zend.

Ahora, algunas personas argumentan que si una biblioteca es lo suficientemente estable y no cambiará con frecuencia, entonces no hay necesidad de ajustarla. Asumiendo que Zend_Mailes estable y no cambiará y se ajusta completamente a mis necesidades, entonces no necesitaré un envoltorio para ello.

Ahora eche un vistazo a mi clase Loggerque depende 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
   }        
}

Sin embargo, las pruebas unitarias requieren que pruebe un componente a la vez, por lo que necesito burlarme de la Zend_Mailclase. Además, estoy violando el principio de Inversión de dependencia , ya que mi Loggerclase ahora depende de la concreción, no de la abstracción.

Ahora, ¿cómo puedo probar Loggerde forma aislada sin envolver Zend_Mail?

El código está en PHP, pero las respuestas no tienen que estarlo. Esto es más un problema de diseño que una característica específica del idioma

Songo
fuente
¿Tienes que usar una interfaz? ¿PHP no admite la escritura de pato?
Kevin Cline
@kevincline bueno, usé PHP porque es el lenguaje que más uso, pero en realidad estoy buscando una solución general al problema, no solo PHP.
Songo

Respuestas:

21

Siempre desea envolver tipos y métodos de terceros detrás de una interfaz. Esto puede ser tedioso y doloroso. A veces puedes escribir un generador de código o usar una herramienta para hacer esto.

Pero no se sienta tentado a usar los métodos o tipos de la biblioteca en todo el código. Para empezar, tendrá problemas para escribir pruebas unitarias. Luego, una licencia cambiará, o querrá ir a una plataforma no admitida por un tercero, y encontrará que esos tipos y dependencias se han entrelazado en todas sus otras clases.

La capacidad de cambiar rápidamente a terceros es una gran ventaja.

Ben
fuente
44
"Cualquier cosa no escrita por ti" es un poco demasiado. Las bibliotecas que forman parte del estándar o la plataforma son difíciles de ajustar. Probablemente no quiera envolver todos los componentes .NET, por ejemplo. Si los contenedores solo pasan a través de interfaces o son código generado, he encontrado pocos beneficios al escribir pruebas. Si hay lógica allí (combinando llamadas, etc.) las pruebas pueden ser útiles.
Ben
3
Votado a favor de la última oración.
Blrfl
1
Si refactoriza adecuadamente, cualquier uso repetitivo de las instalaciones de la biblioteca se incluirá en una clase de servicio. No es necesario definirlo por adelantado.
Kevin Cline
3
-1: Excepto en los casos en que la biblioteca de terceros proporciona un servicio para el que hay una API estandarizada, esta es una gran pérdida de tiempo y solo reducirá la capacidad de mantenimiento al duplicar el código. Además, YAGNI.
Michael Borgwardt
1
@MichaelBorgwardt: Claro, pero en ese caso, la API estándar se convierte en el contenedor y puede intercambiar bibliotecas fácilmente.
Blrfl