PHPUnit 测试真实示例

2022-08-30 21:15:42

我创建了一个邮件包装类。我知道有很多图书馆可以发送电子邮件,但我想学习TDD...所以,我创建了一些测试,我有一些代码。现在我可以在构造函数上设置电子邮件地址并验证它...如果电子邮件地址错误,则会出现异常。电子邮件地址是唯一一个必填字段...我没有设置和获取,因为用户将在构造函数上设置所有电子邮件数据。

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

现实世界的TDD示例对我来说很难。我试图学习它,我读过很多东西,但我无法测试真正的代码。

谢谢。


答案 1

由于您链接到了 mail 函数,因此 对 的调用可能会硬编码到您的代码中。所以看看mail

安装测试助手扩展并模拟对 的调用。然后让模拟验证它在调用包装器的 send 方法时是否被正确的值调用,例如,在某个地方定义一个自定义邮件函数:mail

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('foo@example.com');
    $results = $testClass->send();

    // assert the result
    $this->assertSame('foo@example.com', $results[0]);
    $this->assertSame('Default Title', $results[1]);
    $this->assertSame('Default Message', $results[2]);
}

请注意,上述假设您的 send 函数将返回调用的结果。mail()

通常,您将始终尝试用 Mock 或 Stub 替换外部子系统(如 sendmail 或数据库或文件系统),因此您可以专注于在外部子系统隔离的情况下测试自己的代码。您不需要测试实际有效的方法。mail

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


答案 2

在纯单元测试中,您不会真正测试是否已发送真正的电子邮件,而是测试是否已调用适当的编程单元(本例中的函数)。我真的不知道如何测试该功能是否真的有效,因为我对电子邮件如何在引擎盖下工作没有深入的了解。所以,我只写我如何做单元测试。mailmail

您可以让类构造函数接受一个可选参数,该参数是执行实际发送电子邮件的实际工作的函数。默认情况下,它将是函数,但在测试设置中,您提供特殊函数,该函数将实际检查是否存在正确的主题,正文和标头。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)功能,但它可能是一个对象实例,你可以传递给被测类。


推荐