开放的编程资料库

当前位置:我爱分享网 > Python教程 > 正文

测试发出输出的代码

场景如下:您有将发出标头和内容的代码,例如,一个前端控制器。你如何测试这个?

答案非常简单,但并不明显:名称空间。

先决条件

对于这种工作方法,假设是:

  • 您的代码发出标头和输出位于全局命名空间以外的命名空间中。

就是这样。考虑到您获取的大多数PHP代码都这样做,并且您遇到的大多数编码标准都需要这样做,可以肯定的是您已经准备好了。如果你不是,现在就去重构你的代码,然后再继续;你稍后会感谢我的。

技术

PHP在PHP5.3中引入了命名空间。正如我们大多数人都清楚的那样,命名空间涵盖类,但它们也涵盖常量和函数——这一事实经常被忽视,在5.6(下周发布!)之前,您不能通过use语句导入它们!

这并不意味着它们不能被定义和使用,但是——它只是意味着您需要手动导入它们,通常是通过requirerequire_once语句。这些在库中通常是令人厌恶的,但对于测试来说,它们工作得很好。

这是我最近采用的一种方法。我创建了一个存在的文件——这是重要的一点,所以请注意——与代码发出头文件和输出位于相同的命名空间中。该文件定义了几个位于全局(又名PHP的内置)命名空间中的函数,以及一个累加器静态对象,然后我可以在我的断言测试中使用它。这是它的样子:

namespace Some\Project;

abstract class Output
{
    public static $headers = array();
    public static $body;

    public static function reset()
    {
        self::$headers = array();
        self::$body = null;
    }
}

function headers_sent()
{
    return false;
}

function header($value)
{
    Output::$headers[] = $value;
}

function printf($text)
{
    Output::$body .= $text;
}

一些注意事项:

  • headers_sent()在这里总是返回false,因为大多数发射器会测试布尔真值并在出现这种情况时提前退出。
  • 我使用了printf()在这里,因为echo不能被覆盖,因为它是PHP语言构造而不是实际函数。因此,如果您使用此技术,您可能必须更改发射器以调用printf()而不是echo。然而,这样做的好处是值得的。
  • 我将输出标记为抽象,以防止实例化;它只能静态使用。

我将上述文件放在我的测试套件中,通常在与测试本身相邻的TestAsset目录下;因为它包含函数,所以我将文件命名为Functions.php。这种组合通常会阻止它以任何方式自动加载,因为测试目录通常不会定义自动加载,或者将位于单独的命名空间下。

然后,在您的PHPUnit测试套件中,您将执行以下操作:

namespace SomeTest\Project;

use PHPUnit_Framework_TestCase as TestCase;
use Some\Project\FrontController;
use Some\Project\Output;                 // <-- our Output class from above
require_once __DIR__ . '/TestAsset/Functions.php'; // <-- get our functions

class FrontControllerTest extends TestCase
{
    public function setUp()
    {
        Output::reset();
        /* ... */
    }

    public function tearDown()
    {
        Output::reset();
        /* ... */
    }
}

从这里开始,您可以像往常一样进行测试——但是当您调用将导致标头或内容发出的方法时,您现在可以测试以查看它们包含的内容:

    public function testEmitsExpectedHeadersAndContent()
    {
        /* ... */

        $this->assertContains('Content-Type: application/json', Output::$headers);
        $json = Output::$body;
        $data = json_decode($json, true);
        $this->assertArrayHasKey('foo', $data);
        $this->assertEquals('bar', $data['foo']);
    }

工作原理

为什么会这样?

PHP在解析函数时会施展魔法。对于类,它会在当前名称空间或导入的名称空间(可能有别名)中寻找匹配的类;如果未找到匹配项,它将停止并引发错误。但是,对于函数,它首先在当前命名空间中查找,如果未找到,则在全局命名空间中查找。最后一部分是关键——这意味着如果您在当前命名空间中重新定义一个函数,它将被用来代替PHP定义的原始函数。这也意味着在与该函数相同的命名空间中运行的任何代码——即使是在另一个文件中定义的——都将使用该函数。

这种技术正是利用了这一事实。

未经允许不得转载:我爱分享网 » 测试发出输出的代码

感觉很棒!可以赞赏支持我哟~

赞(0) 打赏