Testing exceptions in PHPunit always fails

It looks like you're masking a different error inside your try/catch. If there is a test assertion within your try block, and that assertion fails, then it is thrown as an exception. Try using setExpectedException instead of a try/catch block:

public function testFirstException() {
    $this->setExpectedException('ExceptionOne');
    $fixture->firstFunction();
}

You should put the setExpectedException call immediately before the line which you expect to throw the exception.

Another alternative is to use the @expectedException docblock annotation.

/**
 * @expectedException ExceptionOne
 */
public function testFirstException() {
    $fixture->firstFunction();
}

If you want to keep the try/catch approach, the same applies: make sure that the only line in the try block is the line which should throw the exception.


From your comments to cbuckley's excellent answer, is appears that the test was written like this:

public function testFirstException() {
    try {
        // some code that is supposed to throw ExceptionOne
        $this->assertTrue(false, "Test failed");
    } catch (Exception $e) {
        $this->assertType('ExceptionOne', $e);
        $this->assertType('MainException', $e);
    }
}

The assertTrue is used to make sure the test fails if the exception isn't thrown during the test. However, this doesn't work because the failed assertion throws a different exception type which causes the error message to be confusing.

Failed asserting that <PHPUnit_Framework_ExpectationFailedException> 
is an instance of class "ExceptionOne".

You can fix this by using either @expectedException or setExpectedException. Not only will the test pass when ExceptionOne is thrown, but it will fail when it isn't thrown or some other exception type is thrown.

/**
 * @expectedException ExceptionOne
 */
public function testFirstException() {
    // some code that is supposed to throw ExceptionOne
}

When no exception is thrown the error message is

Failed asserting that exception of type "ExceptionOne" is thrown.

and when different type of exception is thrown you'll see

Failed asserting that exception of type "Exception" matches
expected exception "RuntimeException".

This method of testing exceptions is

  • easier to write,
  • easier to read,
  • easier to debug when the test fails,
  • and correct.