包装第三方代码是否是对用户进行单元测试的唯一解决方案?


13

我正在进行单元测试,并且在我的一个类中,我需要从一种方法中发送邮件,因此使用构造函数注入,我将注入Zend_MailZend框架中的类的实例。

现在有人认为,如果一个库足够稳定并且不会经常更改,那么就无需对其进行包装。因此,假设这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中,但不一定必须提供答案。这更多的是设计问题,而不是特定于语言的功能


您必须使用界面吗?PHP不支持鸭子输入吗?
凯文·克莱恩

@kevincline好,我使用了PHP,因为它是我使用最多的语言,但是我实际上是在寻找一种通用的解决方案,不仅限于PHP。
Songo 2012年

Answers:


21

您始终希望将第三方类型和方法包装在接口后面。这可能是乏味且痛苦的。有时,您可以编写代码生成器或使用工具来执行此操作。

但是不要试图在整个代码中使用库方法或类型。首先,您将难以编写单元测试。然后,许可证将更改,或者您想要转到第三方不支持的平台,并且您会发现这些类型和依赖关系已经编织在您所有其他类的内部和周围。

快速更换第三方供应商的能力是一个巨大的优势。


4
“任何不是您写的东西”都太多了。作为标准或平台一部分的库很难包装。例如,您可能不想包装所有.NET组件。如果包装器只是通过接口传递,或者是生成的代码,我发现编写测试几乎没有好处。如果其中存在逻辑(合并调用等),则测试可能会有所帮助。
2012年

3
为最后一句话投票。
Blrfl 2012年

1
如果您正确地进行重构,则对库设施的任何重复使用都将被排除在服务类之外。无需预先定义它。
凯文·克莱恩

3
-1:除非第三方库提供具有标准化API的服务,否则这将浪费大量时间,并且只会通过重复代码来降低可维护性。还有,YAGNI。
Michael Borgwardt 2012年

1
@MichaelBorgwardt:可以,但是在那种情况下,标准API成为包装器,您可以轻松地交换库。
Blrfl 2012年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.