Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to change PHPUnit error messages to show custom errors

I have extended PHP Exception with my own to add additional data:

class MyException extends Exception {
   public $foo = [];

   public function __construct($message = '', $data = null, $code = 0) {
       $this->foo = $data;

       paret::__construct($message, $code);
   }
}

When doing normal requests these errors logs correctly and I do not want to add any additional content to $this->message.


When running test I can throw it:

if (!$this->save()) {
    throw new MyException('Internal Server Error', ['log' => 'missing data'], 500);
}

and PHPUnit will output:

MyException: Internal Server Error

I want:

MyExeption: Internal Server Error; {"log": "missing data"}


How to extend PHPUnit to be able to show $myException->foo along with error message?


Sample code:

<?php

class SampleTest extends CTestCase
{
    public function testIndex()
    {
        $this->assertTrue($this->save());
    }

    protected function save()
    {
        $model = new Orders();
        $model->addError('id', 'ID is Required');

        if (!$model->validate()) {
            throw new HttpApiModelException(500, 'Failed to save', $model);
        }

        return true;
    }
}

Executed with command common/vendor/bin/phpunit --configuration tests/phpunit.xml --verbose tests/functional/SampleTest.php

And output:

enter image description here

like image 517
Justinas Avatar asked Mar 07 '26 00:03

Justinas


2 Answers

I am not sure if this is the best option but you could implement test results printer, smth like:

<?php

namespace Tests;

use PHPUnit\TextUI\ResultPrinter;

class TestPrinter extends ResultPrinter
{
    protected function printDefect(\PHPUnit\Framework\TestFailure $defect, $count)
    {
        $this->printDefectHeader($defect, $count);

        $ex = $defect->thrownException();
        // you can do whatever you need here, 
        // like check exception type, etc,
        // printing just line number here
        $this->write('Line #' . $ex->getLine() . "\n");

        $this->printDefectTrace($defect);
    }
}

and register as a printer to be used (assume xml config but could be done via command line as well):

<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:noNamespaceSchemaLocation="http://schema.phpunit.de/4.1/phpunit.xsd"
         backupGlobals="false"
         colors="true"
         bootstrap="vendor/autoload.php"
         printerClass="Tests\TestPrinter"
>
    <!-- note printerClass attribute above -->
</phpunit>

Doing so, you would get output looking similar with:

There was 1 error:

1) Tests\SomeTest::testStuff
Line #16
LogicException: whatever

(I just made a simple test doing throw new \LogicException('whatever');)

like image 184
xmike Avatar answered Mar 10 '26 14:03

xmike


So if you need this data to be printed everytime when you are running tests but not when it's on production then why not to extend the base Exception class and to check if you are under test environment then to concatenate the message and the data. And then all of your custom exceptions to extend this new Exception class.

class BaseException extends Exception {

   public function __construct($message = '', $data = null, $code = 0) {
       if (env('ENVIRONMENT') === 'test') {
           $message .= ' ' . json_encode($data);
       }

       paret::__construct($message, $code);
   }
}

But this implementation will require to change your MyException class to call the parent constructor with this data.

Instead of this

paret::__construct($message, $code);

Now you are going to have this

paret::__construct($message, $data, $code);

And also to extend the new BaseException class to these exception which you want to have this functionality

like image 37
Denis Avatar answered Mar 10 '26 14:03

Denis