使用CakePHP的集成测试用例如何测试异常?

How to test exceptions when using CakePHP's integration test case?

我正在尝试测试我的 CakePHP 3 内部错误异常。

我的控制器:

public function getConfirmation()
{
    if (!$this->request->getData())
        throw new InternalErrorException(__('data not found'));

    $confirmStatus = $this->XYZ->getConfirmation($this->request->getData('ID'), $this->request->getData('MANAGER_ID'));

    $this->set([
        'confirmStatus' => ($confirmStatus) ? 1 : 0,
    ]);
}

在异常测试中,我按照 Sebastian Bergmann's blog 上的建议添加了 expectException,我认为这是个好主意:

public function testInternalErrorExceptionIsRaised()
{
    $this->enableCsrfToken();
    $this->enableSecurityToken();
    $formPostData = [];
    $_SERVER['HTTP_X_REQUESTED_WITH'] = 'XMLHttpRequest';

    $this->expectException(\Cake\Network\Exception\InternalErrorException::class);
    $this->post(
        [
            'controller' => 'XYZ',
            'action' => 'getConfirmation'
        ],
        $formPostData
    );

    $this->assertResponseFailure();
    $this->assertResponseCode(500);
}

错误:

1) App\Test\TestCase\Controller\XYZControllerTest::testInternalErrorExceptionIsRaised

Failed asserting that exception of type "Cake\Network\Exception\InternalErrorException" is thrown.

我尝试了各种方法,但无法测试 CakePHP 3 异常。我也试过 expectExceptionCode()expectExceptionMessage,但没有成功。是否可以测试异常?

在控制器(集成)测试中,默认情况下异常不会进入 PHPUnits 异常处理程序。

这是由于您的应用程序使用了错误处理程序中间件(请参阅 src/Application.php),它将捕获在其包装的代码中抛出的异常,并相应地呈现错误 page/response,或者因为集成测试用例做了类似的事情,即它会捕获可能的异常(\PHPUnit\Exception\Cake\Database\Exception\DatabaseExceptionLogicException 除外)并呈现错误 page/response,这样异常就不会冒泡到 PHPUnits 异常处理程序,这可以防止测试执行停止,并允许您测试异常对象以及应用程序生成的输出(例如错误页面)。

长话短说,在控制器测试中,如果您的应用程序没有使用错误处理程序中间件[=38],您必须手动测试抛出的异常=],这可以通过测试 \Cake\TestSuite\IntegrationTestCase::$_exception 属性 来完成,像这样:

$this->assertEquals(\Cake\Network\Exception\InternalErrorException::class, $this->_exception);

(此外,您还可以像往常一样通过 \Cake\TestSuite\IntegrationTestCase::assertResponse*() 方法或 \Cake\TestSuite\IntegrationTestCase::$_response 属性 等方法测试响应)

或者如果您的应用程序确实使用错误处理程序中间件,并且您想测试异常对象而不是生成的错误response/page,您已确保错误处理程序中间件正在 "excluded",分别重新抛出异常,例如可以通过 \Cake\TestSuite\IntegrationTestCase::disableErrorHandlerMiddleware() 方法实现,该方法自 CakePHP 3.5 起可用.0,像这样:

$this->disableErrorHandlerMiddleware();

// ...
$this->post(/* ... */); // < exception will be triggered there and halt the test

这样做时,您可以/必须使用 PHPUnit 的异常断言功能,即注释或 expectException*() 方法。