简体   繁体   中英

How to execute code after trigger_error(…, E_USER_WARNING) in unit test (PHPUnit)?

I have code like this:

class ToBeTested
{
  function simpleMethod($param)
  {
    if(0 === $param)
    {
      trigger_error("Param is 0!", E_USER_WARNING);
      return false;
    }

    return true;
  }
}

and test for this code:

class SimpleTest extends PHPUnit_Framework_TestCase
{
   function testSimpleMethod()
   {
     $toBeTestedObject = new ToBeTested();
     $this->assertFalse($toBeTestedObject->simpleMethod(0));
   }
}

I know how to test, if the error is triggered ( $this->setExpectedException() ), but I don't know how to execute the code after trigger_error() function.

Remember that in PHPUnit E_USER_WARNING is not converted into PHPUnit_Framework_Error_Warning (which can be disabled), but it is converted into PHPUnit_Framework_Error (which can't be disabled).

This is one of those places where you are 'officially' allowed to use the @ operator :)

Make one test to check the return value, another test to check if the warning gets triggered. And by the way, I'd suggest you do test if the warning is triggered.

class SimpleTest extends PHPUnit_Framework_TestCase
{
   function testSimpleMethodReturnValue()
   {
     $toBeTestedObject = new ToBeTested();
     $this->assertFalse(@$toBeTestedObject->simpleMethod(0));
   }

   /**
    * @expectedException PHPUnit_Framework_Error
    */
   function testSimpleMethodEmitsWarning() {
     $toBeTestedObject = new ToBeTested();
     $toBeTestedObject->simpleMethod(0);
   }
}

What you should be using is set_error_handler() ( link ) and restore_error_handler() which lets you set a function to deal with errors of a given type. It also has the added bonus of giving you a place to test the warning at the same time.

So, something like this:

class SimpleTest extends PHPUnit_Framework_TestCase
{
   function testSimpleMethod()
   {
     set_error_handler(array($this, '_handleWarnedMethod'), E_USER_WARNING);

     $toBeTestedObject = new ToBeTested();
     $this->assertFalse($toBeTestedObject->simpleMethod(0));

     restore_error_handler();
   }

   private function _handleWarnedMethod($errno, $errstr)
   {
      $this->assertEquals(E_USER_WARNING, $errno);
      $this->assertEquals('Param is 0!', $errstr);
   }

}

As always, error suppression isn't the best idea :)

The answer is that in PHPUnit 3.4.15 there is PHPUnit_Util_ErrorHandler class with handleError method which is executed when any error occurs. For error like E_USER_* this method always throws PHPUnit_Framework_Error , so execution of the rest of code is stopped.

The only way to prevent this is to disable user errors reporting, I think. It could be done like this:


class SimpleTest extends PHPUnit_Framework_TestCase
{
   function testSimpleMethod()
   {
      $toBeTestedObject = new ToBeTested();
// disable user errors reporting $oldReportingLevel = error_reporting(); error_reporting($oldReportingLevel ^ (E_USER_ERROR | E_USER_WARNING | E_USER_NOTICE));
// check the condition $this->assertFalse($toBeTestedObject->simpleMethod(0));
// recover old error reporting level error_reporting($oldReportingLevel); } }

Nearly 9 years later, and this question still comes up regularly.

You can use Netsilik/BaseTestCase (MIT License) to get extended functionality to assert errors/warnings are triggered as expected:

composer require netsilik/base-test-case


Testing for a E_WARNING :

<?php
namespace Tests;

class MyTestCase extends \Netsilik\Testing\BaseTestCase
{
    /**
     * {@inheritDoc}
     */
    public function __construct($name = null, array $data = [], $dataName = '')
    {
        parent::__construct($name, $data, $dataName);

        $this->_convertNoticesToExceptions  = false;
        $this->_convertWarningsToExceptions = false;
        $this->_convertErrorsToExceptions   = true;
    }

    public function test_whenWarningTriggered_weCanTestForIt()
    {
        $foo = new Foo();
        $foo->bar();

        self::assertErrorTriggered(E_WARNING, 'The warning string');
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM