3

I have div() in Cal class in my CalTest class has following methods to test the div().

public fucnction div($a,$b){
   if($b == 0){
    throw new Exception("Divided by zero");
   }
   return $a/$b
}

I can pass only testDiv() but testDiv2().

enter image description here

I want to catch check wheather the exeption thrown correctly using PHPUnit. What am I missing here?? Your help is highly appreciated. Thank you!

enter image description here

vascowhite
  • 18,120
  • 9
  • 61
  • 77
Ruwantha
  • 2,603
  • 5
  • 30
  • 44
  • possible duplicate of [PHPUnit assert that an exception was thrown?](http://stackoverflow.com/questions/5683592/phpunit-assert-that-an-exception-was-thrown) – Corbin May 04 '12 at 11:05
  • Hmm, it looks like you have the annotation correct, actually (so perhaps not a duplicate). Have you tried removing the tabs between the annotation @ and the exception name? Edit: Actually, I think the problem is that your expectedMessage is not the exception message. – Corbin May 04 '12 at 11:07
  • @Corbin I read that question and tried it and Tried with different exceptions . But no result – Ruwantha May 04 '12 at 11:09
  • Does PHPUnit automatically catch exceptions? Do you not have to do a try/catch block? – Anthony May 04 '12 at 11:47
  • @Anthony No, you do it in the comment block as RJ has done. – vascowhite May 05 '12 at 06:42
  • @vascowhite - Can you show me where they are catching the error, as I only see the method being called and throwing the exception, no sign of a catch. So I'd like to know if I'm blind or if there a try/catch syntax that I'm unaware of (and might like to start using). – Anthony May 05 '12 at 12:58
  • @Anthony See here http://www.phpunit.de/manual/3.7/en/writing-tests-for-phpunit.html#writing-tests-for-phpunit.exceptions – vascowhite May 05 '12 at 14:16

6 Answers6

4

Your 2nd screenshot (the one with the error) has

"@expectedException Exception"

while the third has

@expectedException InvalidArgumentException

Do you really still get the error? Did you save the file?


Works for me:

Foo.php

<?php

class Foo
{
    static function t()
    {
        throw new InvalidArgumentException('Hi there');
    }
}

?>

FooTest.php

<?php
require_once 'Foo.php';
class FooTest extends PHPUnit_Framework_TestCase
{
    /**
     * @expectedException InvalidArgumentException
     */
    public function testT()
    {
        Foo::t();
    }
}

?>

Result

$ phpunit .
PHPUnit 3.6.10 by Sebastian Bergmann.

.

Time: 0 seconds, Memory: 5.25Mb

OK (1 test, 1 assertion)
cweiske
  • 30,033
  • 14
  • 133
  • 194
3

Just came across the same issue. For some reason PHPUnit will not allow you to set the expectedException to a generic exception and I am not sure why. Personally I opt to throw custom Exception codes rather than have to create a new exception class every time I want to differentiate exceptions.

Here is how I got around it:

/**
 * @expectedException Test_Exception
 */
public function testDivByZero()
{
    try {
        // Fyi you don't need to do an assert test here, as we are only testing the exception, so just make the call
        $result = $this->object->div(1,0);
    } catch (Exception $e) {
        if ('Exception' === get_class($e)) {
            throw new Test_Exception($e->getMessage(), $e->getCode());
        }
    }
 }

 // Test_Exception.php
 class Test_Exception extends Exception
 {
     public function __construct($message = null, $code = 0, Exception $previous = null)
     {
         parent::__construct($message, $code, $previous);
     }
 }

This will allow you to engineer your code the way you want, and throw "generic" exceptions. Basically it just tests the Exception class and if it's generic, re-wrap it as a different exception; Test_Exception.

-- Update --

Found out yesterday that they have removed the generic exception restriction in the current "master" branch, which will be 3.7. Apparently the lead engineer has no desire of patching 3.6.

Mike Purcell
  • 19,847
  • 10
  • 52
  • 89
2

It says so in the exception thrown by PHPUnit:

You must not except the generic exception class.

Make your class throw more detailed Exceptions, and further specify the exception type your expecting in your unit test.

Rijk
  • 11,032
  • 3
  • 30
  • 45
  • Even I expect InvalidArgumentException it is not working. I think it is not generic exception class , right ?? – Ruwantha May 04 '12 at 11:41
  • You are throwing a generic exception though aren't you? – vascowhite May 04 '12 at 11:46
  • @vascowhite : what should I do then shall I throw InvalidArgumentException then ? – Ruwantha May 05 '12 at 02:06
  • If that's what your telling PHPUnit to expect, then its logical that that is what you should be throwing isn't it? – vascowhite May 05 '12 at 06:43
  • 2
    This is a terrible suggestion. Having a vendor API dictate how to engineer code is a bad practice. IMO PHPUnit dropped the ball on this one. Some of us opt for exception codes rather than throwing custom exceptions. – Mike Purcell May 24 '12 at 20:07
2

This problem has been fixed in PHPUnit 3.7.x

You can use the following Generic Exception in PHPUnit 3.7.x

    /**
     * @expectedException Exception     
     */
Developer
  • 25,073
  • 20
  • 81
  • 128
0

you can do something like this

write your unit test so you inject the values required to trigger the exception then

//assert $this->assertTrue($this->setExpectedException('PHPUnit_Framework_ExpectationFailedException'));

jsteinmann
  • 4,502
  • 3
  • 17
  • 21
  • 1
    I'm not clear with what you said, Are you telling met to insert this code to testDiv() or something else ? I tried that after you tall but still the same :'( – Ruwantha May 07 '12 at 04:16
  • I dont understand your comment, but i would suggest using the phpunit resources. http://www.phpunit.de/manual/3.2/en/writing-tests-for-phpunit.html#writing-tests-for-phpunit.exceptions – jsteinmann Nov 26 '12 at 02:05
0

I create a parent class method to do it. In fact, this class came from the laravel but is valid in any context.

The cool part of this method is using anonymous functions into PHP

<?php
class TestCase 
         /* if you are not using laravel, you dont need this 
        extends Illuminate\Foundation\Testing\TestCase */ {

    protected function assertThrows( $function , $classException = "/Exception" )
    {
        try 
        {
            // Anonymous functions FTW
            $function();
        }
        catch( /Exception $objException )
        {
            // the assertInstanceOf should solve from here but
            // it is not working that great
            // @see http://stackoverflow.com/questions/16833923/phpunit-assertinstanceof-not-working
            if( $objException instanceof $classException ) {
                return $this->assertTrue( true );
            } else {
                // this will throw a error with a cool message
                return $this->assertEquals( $classException  , get_class( $objException ));
            }
        }
        // no exception happened.
        return $this->fail( "Exception " . $classException . " expected." );
    }

}

class LanguageTest extends TestCase {

    /**
     * Test the translation
     *
     * @return void
     */
    public function testTranslation()
    {
        // this test may be ok
        $this->assertThrows( 
            function(){ throw new Full\Path\Exception(":("); }, 
            "Full\Path\Exception" );

        // this test may fail 
        $this->assertThrows( 
            function(){ return 1 + 1; }, 
            "Some\Excepted\Exception" );

        // this test may work 
        $this->assertThrows( 
            function(){ throw new Exception( "sad" ); }
        );
    }

} 
Thiago Mata
  • 2,825
  • 33
  • 32