【问题标题】:How to test exceptions when using CakePHP's integration test case?使用 CakePHP 的集成测试用例时如何测试异常?
【发布时间】:2018-10-19 11:06:11
【问题描述】:

我正在尝试测试我的 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

无法断言“Cake\Network\Exception\InternalErrorException”类型的异常被抛出。

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

【问题讨论】:

    标签: unit-testing exception cakephp integration-testing cakephp-3.x


    【解决方案1】:

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

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

    长话短说,在控制器测试中,您必须手动测试抛出的异常,以防您的应用程序使用错误处理程序中间件,这可以通过测试来完成\Cake\TestSuite\IntegrationTestCase::$_exception 属性,如下所示:

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

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

    或者如果您的应用程序确实使用错误处理程序中间件,并且您想测试异常对象而不是生成的错误响应/页面,您必须确保错误处理程序中间件被“排除”,即异常被重新抛出,例如可以通过 \Cake\TestSuite\IntegrationTestCase::disableErrorHandlerMiddleware() 方法实现,该方法从 CakePHP 3.5.0 开始可用,如下所示:

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

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

    【讨论】:

    • 感谢您的帮助和解释。出于某种原因,我的 _exception 值为 NULL,并没有多大用处。虽然,$this-&gt;_response 提供了正确的状态码。我正在测试: $this->assertResponseError(); $this->assertResponseCode(404);
    • 嗯,是的,我忘记了随着错误处理程序中间件的引入,情况发生了怎样的变化,它将吞噬异常。我会更新我的答案。
    • 谢谢@ndm。你是明星。是的,这就像一个魅力。
    猜你喜欢
    • 2022-01-02
    • 2018-03-10
    • 1970-01-01
    • 2014-08-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多