如何让PHPUnit停止拦截异常?

时间:2015-11-02 11:34:01

标签: php json api phpunit web-api-testing

我正在使用一个内部框架,其中每个异常都被错误处理程序捕获并返回适当的JSON错误响应,适用于RESTFul API。

然后我有一套测试,它们是API测试,主要测试API返回带有预期错误代码的正确JSON响应。

对于每个测试,修改(然后恢复)全局变量以模拟不同的HTTP请求。我是这样做的,以避免执行cURL测试(通过Guzzle或类似)的过载,并导致在CLI环境下,代码不知道服务器的URL。

<?php
// ... example, part of a base ApiTestCase class:

// Override globals (should be backed up by PHPUnit)
$_SERVER['REQUEST_METHOD']     = $request->method;
$_SERVER['QUERY_STRING']       = http_build_query($request->parameters);
$_SERVER['PATH_INFO']          = $request->path;
$_SERVER['REQUEST_URI']        = $request->path . ($_SERVER['QUERY_STRING'] ? '?' : '') . $_SERVER['QUERY_STRING'];
$_SERVER['REQUEST_TIME']       = time();
$_SERVER['REQUEST_TIME_FLOAT'] = microtime(true);
$_SERVER['HTTP_COOKIE']        = '';

// Set headers, cookies and parameters
foreach ($request->headers as $k => $v) {
  $_SERVER['HTTP_' . strtoupper(str_replace('-', '_', trim($k)))] = $v;
}
if ($_SERVER['HTTP_COOKIE']) {
  $GLOBALS['_COOKIE'] = http_parse_cookie($_SERVER['HTTP_COOKIE']);
} else {
  $GLOBALS['_COOKIE'] = [];
}
$GLOBALS['_REQUEST'] = $request->parameters;

$responseBody = $app->start();

$response->httpCode = http_response_code();
$response->body     = $responseBody ? @json_decode($responseBody) : null;
$response->headers  = headers_list();

(我知道以这种方式改变全局变量并不好,框架不应该直接依赖全局变量,但我还是要处理遗留代码。)

然后出现了问题:当我尝试测试JSON错误响应时:PHPUnit拦截抛出的异常(在我开头提到的处理程序之前),因此框架没有机会将其转换为JSON并返回正确的响应

我试图在PHPUnit手册中找到一些东西来禁用PHPUnit错误处理程序而没有运气。

在这种情况下我该怎么办?感谢

3 个答案:

答案 0 :(得分:0)

为了清楚起见,听起来我们实际上并没有谈到在这里捕捉异常;我们正在讨论使用PHP set_error_handler()在终止程序之前拦截致命错误。这将处理错误和未捕获的异常。

你无法做的一件事就是让那些错误和异常落到你的错误处理函数中 - 正如你已经发现的那样,phpUnit做了自己的错误处理,你不能这样做覆盖(因为它对phpUnit的工作方式有点基础)。

您需要做的是告诉phpUnit您期待什么样的例外或错误;然后,根据是否发生错误,您的测试将通过或失败。你不会运行错误处理程序,但事实上,你不应该这样做;如果需要,你可以单独测试功能。对于错误条件,您不需要每次都看到错误处理程序产生正确的输出,只是发生了将触发处理程序的错误。

对于常规PHP异常,您可以在测试函数上方使用phpUnit&#39; @expectedException注释,如下所示:

/**
 * @expectedException YourExpectedExceptionClass
 */
function testThisWillThrowAnException() {
    ....
}

如果PHP代码预计会产生PHP错误(即错误,而不是异常),那么您将使用相同的想法,但phpUnit为错误提供了帮助程序类名:PHPUnit_Framework_Error。所以你的代码看起来像这样:

/**
 * @expectedException PHPUnit_Framework_Error
 */
function testThisWillProduceAPHPError() {
    ....
}

在任何一种情况下,如果发生预期的错误/异常,您的测试将通过。

如果异常类本身不足以让您知道测试是否已按照您的意有关详细信息,请参阅the phpUnit manual page for annotations

答案 1 :(得分:0)

上面的示例也是正确的,我的只提供异常作为断言,并为您提供Exceptions Works的知识。

/**
 * @dataProvider fixturesProvider // its just example
 */
public function testDataIsWrong($fixtures)
{
    try
    {
        //Some Code
        $this->fail('Exception');
    }
    catch(Exception $ex)
    {
        $this->assertEquals($ex,'Exception');
    }
}

这也为您的代码提供了可能性,即您可以测试错误或无符号数据并断言它是不正确的。

答案 2 :(得分:0)

我实现的解决我问题的唯一解决方案是不委托异常处理程序负责构建和发送API错误响应,但是在应用程序的顶层捕获异常。

在catch中我有一个异常错误响应转换器来处理它(或者在方便时重新抛出异常),因此不重要的错误(如产生HTTP 4xx响应的错误)是不再出现在PHPUnit测试中了。 我的PHPUnit测试现在也可以处理PSR-7 HTTP响应对象,而不是捕获输出缓冲区。