Является ли упаковка стороннего кода единственным решением для модульного тестирования своих потребителей?

13

Я делаю модульное тестирование, и в одном из моих классов мне нужно отправить письмо от одного из методов, поэтому, используя инъекцию конструктора, я внедряю экземпляр Zend_Mailкласса, который находится в среде Zend.

Теперь некоторые люди утверждают, что если библиотека достаточно стабильна и не будет часто меняться, то нет необходимости ее оборачивать. Если предположить, что Zend_Mailэто стабильно и не изменится и полностью соответствует моим потребностям, тогда мне не понадобится обертка для него.

Теперь взгляните на мой класс, Loggerкоторый зависит от 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
   }        
}

Тем не менее, модульное тестирование требует, чтобы я тестировал по одному компоненту за раз, поэтому мне нужно издеваться над Zend_Mailклассом. Кроме того, я нарушаю принцип инверсии зависимости, поскольку мой Loggerкласс теперь зависит от конкреции, а не абстракции.

Теперь, как я могу тестировать Loggerв изоляции без упаковки Zend_Mail?

Код написан на PHP, но ответы не должны быть. Это скорее проблема дизайна, чем особенность языка

Songo
источник
Вы должны использовать интерфейс? Разве PHP не поддерживает утку?
Кевин Клайн
@kevincline хорошо, я использовал PHP, потому что это язык, который я использую больше всего, но я на самом деле ищу общее решение проблемы, не ограничиваясь только PHP.
Сонго

Ответы:

21

Вы всегда хотите обернуть сторонние типы и методы за интерфейс. Это может быть утомительно и больно. Иногда вы можете написать генератор кода или использовать инструмент для этого.

Но не поддавайтесь искушению использовать библиотечные методы или типы в вашем коде. Для начала у вас будут проблемы с написанием юнит-тестов. Затем лицензия изменится, или вы захотите перейти на платформу, не поддерживаемую третьей стороной, и обнаружите, что эти типы и зависимости переплетены между всеми вашими другими классами.

Возможность быстрой смены сторонних поставщиков является огромным преимуществом.

Бен
источник
4
«Ничего не написанного тобой» - это немного. Библиотеки, являющиеся частью стандарта или платформы, сложно обернуть. Вы, вероятно, не захотите обернуть все компоненты .NET, например. Если обертки просто проходят через интерфейсы или генерируют код, я не нашел большого преимущества в написании тестов. Если там есть логика (объединение вызовов и т. Д.), Тесты могут быть полезны.
Бен
3
Проголосовал за последнее предложение.
Blrfl
1
Если вы правильно проведете рефакторинг, любое повторное использование библиотечных средств будет преобразовано в класс обслуживания. Нет необходимости определять это заранее.
Кевин Клайн
3
-1: За исключением случаев, когда сторонняя библиотека предоставляет сервис, для которого есть стандартизированный API, это огромная трата времени и только снизит удобство обслуживания, если вы дублируете код. Также ЯГНИ.
Майкл Боргвардт
1
@MichaelBorgwardt: Конечно, но в этом случае стандартный API становится оболочкой, и вы можете легко менять библиотеки.
Blrfl