3

I'm trying to test my CakePHP 3 Internal error Exception.

My Controller:

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,
    ]);
}

In the exception test, I've added expectException as suggested on Sebastian Bergmann's blog and I think it is a good idea:

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);
}

Error:

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

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

I've tried various ways, but was not able to test CakePHP 3 exception. I have tried expectExceptionCode() and expectExceptionMessage as well, but no luck. Is it possible to test the exception?

ndm
  • 59,784
  • 9
  • 71
  • 110
Invincible
  • 1,418
  • 18
  • 23

1 Answers1

2

In controller (integration) tests, exceptions by default won't make it to PHPUnits exception handler.

This is caused by either your application using the error handler middleware (see src/Application.php), which will catch the exception thrown in the code that it wraps, and renders an error page/response accordingly, or because of the intergration test case doing something similar, that is, it will catch possible exceptions (except for \PHPUnit\Exception, \Cake\Database\Exception\DatabaseException and LogicException) and render an error page/response, so that the exceptions do not bubble up to PHPUnits exception handler, this prevents the test execution from being halted, and allows you to test both, the exception object, as well as the output (an error page for example) generated by your application.

Long story short, in controller tests you have to either manually test for thrown exceptions in case your application does not use the error handler middleware, which can done by testing the \Cake\TestSuite\IntegrationTestCase::$_exception property, like this:

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

(additionally you can then test the response as usual via for example the \Cake\TestSuite\IntegrationTestCase::assertResponse*() methods, or the \Cake\TestSuite\IntegrationTestCase::$_response property)

or if your application does use the error handler middleware, and you want to test the exception object instead of the generated error response/page, you have ensure that the error handler middleware is being "excluded", respectively that exceptions are being rethrown, which can for example be achieved via the \Cake\TestSuite\IntegrationTestCase::disableErrorHandlerMiddleware() method, which is available as of CakePHP 3.5.0, like this:

$this->disableErrorHandlerMiddleware();

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

When doing so, you can / have to use PHPUnits exception assertion functionality, ie annoations or the expectException*() methods.

ndm
  • 59,784
  • 9
  • 71
  • 110
  • Thanks for your help and explanation. For some reason, my `_exception` value is NULL and not much useful. Although, the `$this->_response` provides correct status code. I'm testing with: $this->assertResponseError(); $this->assertResponseCode(404); – Invincible Oct 19 '18 at 12:31
  • 1
    Mmmm, yeah, I forgot how things have changed with the introduction of the error handler middleware, which will swallow the exceptions. I'll update my answer. – ndm Oct 19 '18 at 13:20
  • Thank you @ndm. You are a star. Yes, that worked like a charm. – Invincible Oct 19 '18 at 14:12