2011-06-14 178 views
18

我创建了一个mail包装类。我知道有很多库可以发送电子邮件,但我想学习TDD ...所以,我创建了一些测试,并且我有一些代码。现在我可以在构造函数上设置电子邮件地址并进行验证......如果电子邮件地址错误,则会引发异常。电子邮件地址是唯一必填字段...我没有集合,因为用户将在构造函数中设置所有电子邮件数据。PHPUnit测试实例

现在,我要写的发送测试。我不知道如何开始它。如果我不想拥有setter和getters,我怎么能测试这些值是否存在(主题,邮件正文,标题)?我如何测试电子邮件是否可以发送?

真实世界的TDD示例对我来说很难。我试着去了解它,我已经阅读了很多东西,但是我无法测试真正的代码。

谢谢。

回答

16

由于您链接到邮件功能,所以对mail的调用很可能会被硬编码到您的代码中。所以看看

安装testhelper extension和模拟调用mail。然后当你的包装器的send方法被调用时,让mock验证它被调用了正确的值。地方定义自定义邮件功能:

function mail_mock() 
{ 
    $allThatWasPassedToTheFunction = func_get_args(); 
    return $allThatWasPassedToTheFunction; 
} 
send()测试

然后,像做

public function testSendReceivesExpectedValues() 
{ 
    // replace hardcoded call to mail() with mock function 
    rename_function('mail', 'mail_orig'); 
    rename_function('mail_mock', 'mail'); 

    // use the wrapper 
    $testClass = new MailWrapper('[email protected]'); 
    $results = $testClass->send(); 

    // assert the result 
    $this->assertSame('[email protected]', $results[0]); 
    $this->assertSame('Default Title', $results[1]); 
    $this->assertSame('Default Message', $results[2]); 
} 

注意的是,上述假设你的发送函数将返回mail()调用的结果。

通常,您将总是尝试用一个Mock or a Stub替代外部子系统,如sendmail或数据库或文件系统,这样您就可以专注于测试自己的代码,并隔离外部子系统。你不需要测试mail实际工作。

另见http://www.phpunit.de/manual/3.6/en/test-doubles.html

2

在纯粹的单元测试,你真的不测试一个真实的电子邮件是否已发送,但适当的编程单元(在mail功能在这种情况下),而是否被调用。我真的不知道如何测试mail函数是否真正起作用,因为我没有深入了解电子邮件如何在底层工作。所以,我只会写我如何做单元测试。

你可以让你的类构造函数接受一个可选的参数,这个函数完成真正发送邮件的功能。默认情况下,它将是mail函数,但在您的测试设置中,您提供了实际将检查正确主题,正文和标题的特殊功能。

测试:

<?php 

class EmailerTest extends PHPUnit_Framework_TestCase 
{ 
    public function testMailFunctionIsCalledWithCorrectArguments() 
    { 
    $actualSubject, $actualBody, $actualHeaders; 
    $mailFunction = function ($subject, $body, $headers) 
     use (&$actualSubject, &$actualBody, &$actualHeaders) { 
     $actualSubject = $subject; 
     $actualBody = $body; 
     $actualHeaders = $headers; 
    }; 

    $emailer = new Emailer($options, $mailFunction); 
    $emailer->send(); 

    $this->assertEquals('Expected subject', $actualSubject); 
    $this->assertEquals('Expected body', $actualBody); 
    $this->assertEquals('Expected headers', $actualHeaders); 
    } 
} 

与被测类:

<?php 

class Emailer 
{ 
    public function __construct($options, $mailFunction = 'mail') 
    { 
    $this->subject = $options->subject; 
    $this->body = $options->body; 
    // etc. 
    $this->mailFunction = $mailFunction; 
    } 

    public function send() 
    { 
    // find out $subject, $body, $headers, and then... 

    call_user_func_array($this->mailFunction, array(
     $subject, 
     $body, 
     $headers 
    )); 
    } 
} 

这是某种形式的伪代码,因为我已经留下了一些值的为你完成或实现。重点是您应该为您正在测试的课程的合作者提供测试双打。

在这种情况下,它只是一个函数(我已经使用了某些PHP 5.3)的特性,但它可能是一个对象实例,您将传递给正在测试的类。

0

我认为这个班级应该对电子邮件,主题和其他信息进行验证,所以我建议这应该分开给功能。

当你有私人验证功能,必须返回特定的结果,那么你可以写断言来测试它。

this article可能是有用的。

我对TDD也很陌生,我选择依靠IDE(Netbeans)来帮助我理解这个过程。

希望对您有所帮助:)

+1

Netbeans如何做到这一点?谢谢。 – thom 2011-06-14 16:59:58

+0

它具有PHPUnit功能,也集成了列出PHPUnit测试功能的代码完成功能。它不是为你做所有的任务,它只是提供方便的工具。试试这篇文章http://netbeans.org/kb/docs/php/phpunit.html – Panuwizzle 2011-06-15 07:29:07