0

I have a class that takes in a dependency. One of the things the class does is catch errors thrown by that dependency (does something useful to log this, and goes on to return a return the rest of the code finds useful.)

In PHPUnit, I can mock up the dependency and test as follows:

    $stubqueryrunner = $this->createStub(QueryRunner::class);
    $stubqueryrunner->method('getArray')->will($this->throwException(new \Error));
    $inner = new myClass("mark", $stubqueryrunner);
    $this->assertEquals(["what" => "", "why" => ""], $inner->getReasons());

The class I'm testing catches any error raised in its dependencies (and returns some default values) for the getReasons method.

My code passes my tests (ie - the Method I'm testing has indeed caught the error and substituted the default values.)

However, the act of raising the error writes many lines of stack trace to the output of PHPUnit.

I can't use the @ operator at the point I call it, because I'm in PHP8, where the stfu operator is deprecated for errors.

I can't use

/**
 * @expectedError PHPUnit\Framework\Error
 */

... because that's not in PHPUnit 9.

So how do I actually suppress all the stack trace stuff from appearing in the PHPUnit console?

Update: Adding $this->expectException(\Error::class); just creates an additional assertion which then immediately fails precisely because the class I'm testing has successfully caught it.

The code I'm testing never actually produces errors. The only thing that's producing an error is the Stub I've written in the Unit test when it runs throwException

Adding error_reporting(0); in the test doesn't help.

  • How about `$this->expectException(\Error::class)`? Or even just `$this->expectError();` – duncan Jul 02 '21 at 15:52
  • That creates an assertion which fails, because (ironically) the test itself doesn't get an error (because the class has correctly caught it). So I get the output --- Failed asserting that exception of type "Error" is thrown. --- – Mark Harrison Jul 02 '21 at 16:54

1 Answers1

0

I can't use the @ operator at the point I call it, because I'm in PHP8, where the stfu operator is deprecated for errors.

The @ operator may be deprecated, but what it does, is not.

Suppress the errors by settings or setting blank the error-handler for the lines of code you used the @ operator previously and you should get it to work (functions that come to mind: error_reporting(), set_error_handler()).

This should then already suppress the error and henceforth even if the Phpunit run configuration is "sharp" and would mark the test as a failed on error (or at least warns, this is what you normally want in testing) as the error has been suppressed before Phpunits test-runner could be noticed by it (the phpunit error handler is set blank when you set your own handler, and active again after you unset it), there is no additional handing of it any longer by Phpunit.

So how do I actually suppress all the stack trace stuff from appearing in the PHPUnit console?

The previous stacktrace may not be fully gone after the change if some internal handling is adding it. One extension that does this I know about is xdebug and the stacktrace might then be caused by runtime configuration.

Take care you're using the right settings in testing or at least don't fear if you still see a stacktrace and can't explain it to yourself.

For Xdebug it's the develop mode in xdebug, remove it and the stack-traces done by xdebug to aid in development are gone.


You should get it to work on the level of the test. This would be the first milestone. Lets assume already being there and add some more context:

You now have two tests:

  1. The original test (that is not sufficient for you under PHP 8, maybe even fails).

  2. The regression (new) test where you take care of the error handling.

I'd say, the (original) test shows, that the code under test itself is not forward compatible with PHP 8. So what has been patched into the (regression) test to get it working should ideally become part of the implementation.

The previous test then should run again, regardless of which version. So you would have the old test, and the new test to test for the regression.


I'd consider this a bit of a luxury problem. Not because its superfluous, but by the description of the error handling, this is not straight forward code so it needs extras in development, testing and maintenance and should have actual a decent staff to take care of these.

See just in testing, its hard. Even the simple things like what the @ operator is and while already seen as the cause of change, it's overly puzzling - why?

It might be because error handling is hard and testing for error handling maybe even harder.


Q/A Reference:

hakre
  • 193,403
  • 52
  • 435
  • 836
  • I think I've explained badly. There are no @ operators in the code under test. That code isn't throwing errors. However, part of what that code is doing is CATCH errors (thrown by a third party legacy library.) The place where I've been adding @ operators is to the PHPUnit code ... ie the Test function. I'm trying to test what happens when the test stub throws an error... to make sure my code is catching it properly, and logging it to the right place (which, in production, it is... I just want better unit test coverage.) The error is being thrown by the stub in the unit test... – Mark Harrison Jul 03 '21 at 16:15
  • Yes, this is where I came from, I first looked only per the test, hence the suggestion to patch the test first. After that milestone, things may vary more - I don't know your code - so if in the end it was only the test-code that had the regression with PHP 8 - I would not complain if I were you - less work :) – hakre Jul 03 '21 at 16:20