2

我正在使用一个内部框架,其中每个异常都由错误处理程序捕获并以适当的 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 错误处理程序,但没有成功。

在这种情况下我能做什么?谢谢

4

3 回答 3

0

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

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

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

于 2015-11-04T12:19:40.370 回答
0

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

您将无法做的一件事是让这些错误和异常落入您的错误处理函数——正如您已经发现的那样,phpUnit 会执行您自己无法覆盖的错误处理(因为它对phpUnit 是如何工作的)。

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

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

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

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

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

无论哪种情况,如果发生预期的错误/异常,您的测试将通过。

您还可以测试特定的异常消息和代码,以防异常类本身不足以让您知道测试是否完成了您希望它执行的操作。有关更多信息,请参阅注释的 phpUnit 手册页

于 2015-11-02T14:41:46.977 回答
0

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

在 catch 中,我有一个异常到错误的响应转换器来处理这个问题(或者在方便时重新抛出异常),所以不重要的错误(比如产生 HTTP 4xx 响应的错误)不会弹出在 PHPUnit 测试中。我的 PHPUnit 测试现在也能够处理 PSR-7 HTTP 响应对象,而不是捕获输出缓冲区。

于 2018-03-26T15:08:52.440 回答