Unit Testing TDD – Is Wrapping Third Party Code the Only Solution to Unit Test Its Consumers?

designobject-orientedsolidtddunit testing

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.

Now some people argue that if a library is stable enough and won't change often then there is no need to wrap it. So assuming that Zend_Mail is stable and won't change and it fits my needs entirely, then I won't need a wrapper
for it.

Now take a look at my class Logger that depends on 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
   }        
}

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.

Now how can I test Logger in isolation without wrapping Zend_Mail?!

The code is in PHP, but answers doesn't have to be. This is more of a design issue than a language specific feature

Best Answer

You always want to wrap third party types and methods behind an interface. This can be tedious and painful. Sometimes you can write a code generator or use a tool to do this.

But don't be tempted to use the library methods or types throughout your code. To begin with, you will have trouble writing unit tests. Then a license will change, or you'll want to go to a platform not supported by the third party, and you will find that those types and dependencies have woven in and around all your other classes.

The ability to change third party vendors quickly is a huge advantage.