I'm doing unit testing and in one of my classes I need to send a mail from one of the methods, so using constructor injection I inject an instance of Zend_Mail class which is in Zend framework.
Example:
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
}
}
However, Unit testing demands that I test one component at a time, so I need to mock the Zend_Mail class. In addition I'm violating the Dependency Inversion principle as my Logger class now depends on concretion not abstraction.
Does that mean that I can never use a library class directly and must always wrap it in a class of my own?
Example:
interface Mailer{
public function setTo($to);
public function setSubject($subject);
public function setBody($body);
public function send();
}
class MyMailer implements Mailer{
private $mailer;
function __construct(){
$this->mail=new Zend_Mail; //The class isn't injected this time
}
function setTo($to){
$this->mailer->setTo($to);
}
//implement the rest of the interface functions similarly
}
And now my Logger class can be happy :D
class Logger{
private $mailer;
function __construct(Mailer $mail){
$this->mail=$mail;
}
//rest of the code unchanged
}
Questions:
Although I solved the mocking problem by introducing an interface, I have created a totally new class Mailer that now needs to be unit tested although it only wraps Zend_Mail which is already unit tested by the Zend team. Is there a better approach to all this?
Zend_Mail's send() function could actually have a Zend_Transport object when called (i.e. public function send($transport = null)). Does this make the idea of a wrapper class more appealing?
The code is in PHP, but answers doesn't have to be. This is more of a design issue than a language specific feature