Permalink
Browse files

New assertion to test if a given exception is thrown.

Note that this is a minimal implementation, for demonstration purposes, with
just enough code to make it work in PHPUnit.
For a longer discussion see:
http://lars-tesmer.com/blog/2011/08/29/phpunit-better-syntax-for-expecting-exceptions/

Example usage:
$someClass = new SomeClass();
$this->assertThrowsException('InvalidArgumentException', function () use($someClass) {
		$someClass->someMethod();
	}
);
  • Loading branch information...
Lars Tesmer
Lars Tesmer committed Aug 29, 2011
1 parent 7f7ad8b commit dd5c7bd71d6eb8d4b58ce79b5ae069fbb0734354
Showing with 84 additions and 0 deletions.
  1. +6 −0 PHPUnit/Framework/Assert.php
  2. +56 −0 PHPUnit/Framework/Constraint/ExceptionThrown.php
  3. +22 −0 Tests/Framework/AssertTest.php
@@ -2071,6 +2071,12 @@ public static function assertNotTag($matcher, $actual, $message = '', $isHtml =
self::assertFalse($matched, $message);
}
public static function assertThrowsException($exceptionName, $code)
{
$constraint = new PHPUnit_Framework_Constraint_ExceptionThrown($exceptionName);
self::assertThat($code, $constraint);
}
/**
* Evaluates a PHPUnit_Framework_Constraint matcher object.
*
@@ -0,0 +1,56 @@
<?php
class PHPUnit_Framework_Constraint_ExceptionThrown extends PHPUnit_Framework_Constraint {
private $_exceptionName;
private $_exceptionThrown = null;
public function __construct($exceptionName)
{
$this->_exceptionName = $exceptionName;
}
/**
* Evaluates the constraint for parameter $other. Returns TRUE if the
* constraint is met, FALSE otherwise.
*
* @param mixed $other Value or object to evaluate.
* @return bool
*/
public function evaluate($code)
{
try {
$code();
} catch (\Exception $e) {
$this->_exceptionThrown = $e;
}
if (!$this->_exceptionThrown) {
return false;
}
if (!$this->_exceptionThrown instanceof \Exception) {
return false;
}
if (!$this->_exceptionThrown instanceof $this->_exceptionName) {
return false;
}
return true;
}
public function customFailureDescription($other, $description, $not)
{
if(!$this->_exceptionThrown || !$this->_exceptionThrown instanceof \Exception) {
$failureDescription = sprintf("Expected exception <%s> but no exception was thrown.", $this->_exceptionName);
} else {
$failureDescription = sprintf("Expected exception: <%s>\nCaught Exception: <%s>.", $this->_exceptionName, get_class($this->_exceptionThrown));
}
return $failureDescription;
}
public function toString()
{
}
}
@@ -4520,4 +4520,26 @@ public function testMarkTestSkipped()
$this->fail();
}
/**
* @covers PHPUnit_Framework_Assert::assertThrowsException
*/
public function testAssertThrowsException()
{
$code = function() {
throw new InvalidArgumentException('test');
};
$this->assertThrowsException('InvalidArgumentException', $code);
try {
$this->assertThrowsException('MyMadeUpException', $code);
}
catch (PHPUnit_Framework_AssertionFailedError $e) {
return;
}
$this->fail();
}
}

2 comments on commit dd5c7bd

@dharkness

This comment has been minimized.

dharkness replied Jun 15, 2012

You could use __staticCall() to move the exception name from a string parameter into the method name. This might make the API a little nicer for the built-in (non-package) exceptions:

self::assertThrowsInvalidArgumentException(function () use($someClass) {
    $someClass->someMethod();
});
@kiltec

This comment has been minimized.

Owner

kiltec replied Jul 13, 2012

Yes, that's a nice idea, will fiddle around with it, to see if it's really better, thanks! :)

Please sign in to comment.