14

I'm not getting how to unit test Exceptions with PHPUnit.

Please see my method with the Exception:

    public function getPhone($html, $tag = 'OFF', $indicative, $number_lenght) {

        // .. code

        if ($tag <> 'OFF') {

            $html = $doc[$tag]->text(); // Apanho apenas o texto dentro da TAG
                if (empty($html)) {
                    throw new Exception("Nao foi possivel apanhar qualquer texto dentro da TAG, Metodo em causa: getPhone()");
                }               
        }

        // .. code
    }

And now my PHPUnit Test:

<?php

require_once '../Scrap.php';

class ScrapTest extends PHPUnit_Framework_TestCase
{

    protected $scrap;

    // Setup function to instantiate de object to $this->scrap
    protected function setUp()
    {
        $this->scrap = new Scrap;
    }

    /**
    * @covers Scrap::getPhone
    * @expectedException Exception
    *
    */
    public function testGetPhone() {

        // Variables1
        $array_static1 = Array(0 => 218559372, 1 => 927555929, 2 => 213456789, 3 => 912345678);
        $phone_list1   = '</div>A Front para<br /><br /><br /><br /><br /><br />-Apoio;<br />-Criação;<br />-Campanhas;<br />-Promoções<br /><br /><br />CONDIÇÕES:<br /><br />Local de Trabalho: Es<br />Folgas: Mistas<br /><br /><br /><br />ordem 500€<br /><br /><br /><br />Mínimos:<br /><br />- Conhecimentos;<br />- Ensino ;<br />-INGLÊS.<br /><br /><br /><br />Candidaturas: <br />[email protected]<br />218559372 | 927 555 929 | <br />RH<br />Rua C. Sal. 40<br />1000-000 Lisboa<br /><br /><br />+351 21 3456789 | (351) 912345678';

        // Variables2
        $array_static2 = Array(0 => 'NA');
        $phone_list2   = "";

        // .. more tests

        // Test Exception, Tag not found
        if (TRUE) {

            // Bloco try/catch para confirmar que aqui lança excepção
            try {            
                    $this->scrap->getPhone($phone_list1, 'hr', '351', '9');        
                }         
            catch (Exception $expected) {
                    return;        
                }         

            $this->fail('An expected exception has not been raised.');  
        }



    }
}
?>

If I run the test I got "Failure":

1) ScrapTest::testGetPhone
Expected exception Exception

FAILURES!
Tests: 1, Assertions: 5, Failures: 1.

The exception raises but I don't want to get failure in the PHPUnit, If the Exception raise, I want to get the test OK.

Can you give me some clues?

Best Regards,

2

2 Answers 2

33

You are doing too much there.

Either use: @expectedException Exception

OR: try / catch / $this->fail

The way you are doing it right now says "catch that exception and THEN expect the code to throw another one!"

The first way is cleaner in my opinion because it's only 1 line against 5 (or even more) lines of code and it's less error prone.

/**
* @covers Scrap::getPhone
* @expectedException Exception
*
*/
public function testGetPhone() {

    // Variables1
    $array_static1 = Array(0 => 218559372, 1 => 927555929, 2 => 213456789, 3 => 912345678);
    $phone_list1   = '...';

    // Variables2
    $array_static2 = Array(0 => 'NA');
    $phone_list2   = "";

    // .. more tests

    // Bloco try/catch para confirmar que aqui lança excepção
    $this->scrap->getPhone($phone_list1, 'hr', '351', '9');        

That should do it.

2
  • 6
    You can also use $this->setExpectedException('ExceptionTypeGoesHere') at the top of your test method, as well as the two listed above. I think this is the cleanest approach.
    – TeaPow
    Commented Mar 13, 2013 at 15:36
  • Exactly. Take a look at dotnetCarpenter's comment for updated guidelines. Commented Nov 8, 2018 at 13:20
14

There are two ways to test thrown exceptions but it depend on your needs. If you don't care about the content/properties of the exception (i.e. code, message, etc), then you can do:

$this->setExpectedException('MyApp\Exception');
$object->someFailingCodeWithException();

Else, if you need to use exception properties for assertion (i.e. code), then you can do the try-catch-fail:

try {
    $object->someFailingCodeWithException();
} catch (MyApp\Exception $e) {
    $this->assertEquals($e->getCode(), 100);
    return;
}

$this->fail();

Notice the return statement inside the catch block. The $this->fail(); statement will/must be only called once there is no exception raised. Thus, this test case fails because it should test the exception which is not thrown in the first place.

3
  • 2
    At least from phpunit 6.1 this doesn't work anymore. You should be as specific as possible when testing exceptions. Testing for classes that are too generic might lead to undesirable side-effects. Accordingly, testing for the Exception class with @expectedException or setExpectedException() is no longer permitted. phpunit.de/manual/current/en/… Commented May 6, 2017 at 16:43
  • 1
    in PHPunit 6+ we need to use public function testGetPhone() { $this->expectException(\InvalidArgumentException::class); some code cause exception here } Commented Sep 14, 2017 at 13:18
  • Works like a charm
    – Invincible
    Commented Jul 20, 2018 at 15:41

Not the answer you're looking for? Browse other questions tagged or ask your own question.