test the return value of a method that triggers an error with PHPUnit

There is no way to do this within one unit test. It is possible if you break up testing the return value, and the notice into two different tests.

PHPUnit's error handler catches PHP errors and notices and converts them into Exceptions--which by definition stops program execution. The function you are testing never returns at all. You can, however, temporarily disable the conversion of errors into exceptions, even at runtime.

This is probably easier with an example, so, here's what the two tests should look like:

public function testLoadFileTriggersErrorWhenFileNotFound()
{
    $this->setExpectedException('PHPUnit_Framework_Error_Warning'); // Or whichever exception it is
    $result = load_file('/some/non-existent/file');

}

public function testLoadFileRetunsFalseWhenFileNotFound()
{
    PHPUnit_Framework_Error_Warning::$enabled = FALSE;
    $result = load_file('/some/non-existent/file');

    $this->assertFalse($result);
}

This also has the added bonus of making your tests clearer, cleaner and self documenting.

Re: Comment: That's a great question, and I had no idea until I ran a couple of tests. It looks as if it will not restore the default/original value, at least as of PHPUnit 3.3.17 (the current stable release right now).

So, I would actually amend the above to look like so:

public function testLoadFileRetunsFalseWhenFileNotFound()
{
    $warningEnabledOrig = PHPUnit_Framework_Error_Warning::$enabled;
    PHPUnit_Framework_Error_Warning::$enabled = false;

    $result = load_file('/some/non-existent/file');

    $this->assertFalse($result);

    PHPUnit_Framework_Error_Warning::$enabled = $warningEnabledOrig;
}

Re: Second Comment:

That's not completely true. I'm looking at PHPUnit's error handler, and it works as follows:

  • If it is an E_WARNING, use PHPUnit_Framework_Error_Warning as an exception class.
  • If it is an E_NOTICE or E_STRICT error, use PHPUnit_Framework_Error_Notice
  • Else, use PHPUnit_Framework_Error as the exception class.

So, yes, errors of the E_USER_* are not turned into PHPUnit's *_Warning or *_Notice class, they are still transformed into a generic PHPUnit_Framework_Error exception.

Further Thoughts

While it depends exactly on how the function is used, I'd probably switch to throwing an actual exception instead of triggering an error, if it were me. Yes, this would change the logic flow of the method, and the code that uses the method... right now the execution does not stop when it cannot read a file. But that's up to you to decide whether the requested file not existing is truly exceptional behaviour. I tend to use exceptions way more than errors/warnings/notices, because they are easier to handle, test and work into your application flow. I usually reserve the notices for things like depreciated method calls, etc.


Use a phpunit.xml configuration file and disable the notice/warning/error to Exception conversion. More details in the manual. It's basically something like this:

<phpunit convertErrorsToExceptions="false"
         convertNoticesToExceptions="false"
         convertWarningsToExceptions="false">
</phpunit>