Answers:
<?php
require_once 'PHPUnit/Framework.php';
class ExceptionTest extends PHPUnit_Framework_TestCase
{
public function testException()
{
$this->expectException(InvalidArgumentException::class);
// or for PHPUnit < 5.2
// $this->setExpectedException(InvalidArgumentException::class);
//...and then add your test code that generates the exception
exampleMethod($anInvalidArgument);
}
}
PHPUnit作者文章提供了有关测试异常最佳实践的详细说明。
$this->setExpectedException('\My\Name\Space\MyCustomException');
expectException()
。虽然对某些人来说可能很明显,但这对我来说却是一个陷阱。
在发布PHPUnit 9之前,您还可以使用docblock批注:
class ExceptionTest extends PHPUnit_Framework_TestCase
{
/**
* @expectedException InvalidArgumentException
*/
public function testException()
{
...
}
}
对于PHP 5.5+(尤其是带有命名空间的代码),我现在更喜欢使用 ::class
IncorrectPasswordException
应该足够-消息等于是"Wrong password for bob@me.com"
辅助消息。此外,您还希望花费尽可能少的时间来编写测试,然后您将开始了解简单测试的重要性。
如果你在PHP 5.5以上运行时,你可以用::class
分辨率来获得与类的名称expectException
/setExpectedException
。这提供了几个好处:
string
因此可以与任何版本的PHPUnit一起使用。例:
namespace \My\Cool\Package;
class AuthTest extends \PHPUnit_Framework_TestCase
{
public function testLoginFailsForWrongPassword()
{
$this->expectException(WrongPasswordException::class);
Auth::login('Bob', 'wrong');
}
}
PHP编译
WrongPasswordException::class
进入
"\My\Cool\Package\WrongPasswordException"
没有PHPUnit是更明智的选择。
注意:引入PHPUnit 5.2
expectException
替代setExpectedException
。
下面的代码将测试异常消息和异常代码。
重要说明:如果也未引发预期的异常,它将失败。
try{
$test->methodWhichWillThrowException();//if this method not throw exception it must be fail too.
$this->fail("Expected exception 1162011 not thrown");
}catch(MySpecificException $e){ //Not catching a generic Exception or the fail function is also catched
$this->assertEquals(1162011, $e->getCode());
$this->assertEquals("Exception Message", $e->getMessage());
}
$this->fail()
我不认为这种方式不会被使用,至少目前不会(PHPUnit 3.6.11);它本身就是一个例外。以您的示例为例,如果$this->fail("Expected exception not thrown")
调用,则会catch
触发该块,并且该块$e->getMessage()
是“未引发预期异常”。
fail
可能属于后 catch块,而不是尝试内。
fail
不应在该try
区域中。它本身会触发catch
生成错误结果的块。
catch(Exception $e)
。当我尝试捕获特定异常时,此方法对我来说效果很好:try { throw new MySpecificException; $this->fail('MySpecificException not thrown'); } catch(MySpecificException $e){}
您可以使用assertException扩展来在一个测试执行期间声明一个以上的异常。
将方法插入TestCase并使用:
public function testSomething()
{
$test = function() {
// some code that has to throw an exception
};
$this->assertException( $test, 'InvalidArgumentException', 100, 'expected message' );
}
我还为喜欢精美代码的爱好者们赋予了一个特质。
assertException
未定义。我也无法在PHPUnit手册中找到它。
asertException
方法不是原始PHPUnit的一部分。您必须继承PHPUnit_Framework_TestCase
该类并手动添加上面发布的链接的方法。然后,您的测试用例将继承此继承的类。
一种替代方法可以是以下方法:
$this->expectException(\InvalidArgumentException::class);
$this->expectExceptionMessage('Expected Exception Message');
请确保您的测试课程范围\PHPUnit_Framework_TestCase
。
PHPUnit expectException
方法非常不便,因为每个测试方法只能测试一个异常。
我使这个辅助函数断言某些函数引发异常:
/**
* Asserts that the given callback throws the given exception.
*
* @param string $expectClass The name of the expected exception class
* @param callable $callback A callback which should throw the exception
*/
protected function assertException(string $expectClass, callable $callback)
{
try {
$callback();
} catch (\Throwable $exception) {
$this->assertInstanceOf($expectClass, $exception, 'An invalid exception was thrown');
return;
}
$this->fail('No exception was thrown');
}
将其添加到您的测试班级,并以这种方式调用:
public function testSomething() {
$this->assertException(\PDOException::class, function() {
new \PDO('bad:param');
});
$this->assertException(\PDOException::class, function() {
new \PDO('foo:bar');
});
}
PHPUnit当前用于异常测试的“ 最佳实践 ”似乎..不足为妙(docs)。
由于我想要的不仅仅是当前的expectException
实现,因此我在测试用例中使用了一个特质。大约只有50行代码。
assert
语法assertNotThrows
Throwable
错误我将AssertThrows
特征发布给Github和packagist,以便可以与作曲家一起安装。
只是为了说明语法背后的精神:
<?php
// Using simple callback
$this->assertThrows(MyException::class, [$obj, 'doSomethingBad']);
// Using anonymous function
$this->assertThrows(MyException::class, function() use ($obj) {
$obj->doSomethingBad();
});
挺整洁的?
请参阅下面的更全面的用法示例:
<?php
declare(strict_types=1);
use Jchook\AssertThrows\AssertThrows;
use PHPUnit\Framework\TestCase;
// These are just for illustration
use MyNamespace\MyException;
use MyNamespace\MyObject;
final class MyTest extends TestCase
{
use AssertThrows; // <--- adds the assertThrows method
public function testMyObject()
{
$obj = new MyObject();
// Test a basic exception is thrown
$this->assertThrows(MyException::class, function() use ($obj) {
$obj->doSomethingBad();
});
// Test custom aspects of a custom extension class
$this->assertThrows(MyException::class,
function() use ($obj) {
$obj->doSomethingBad();
},
function($exception) {
$this->assertEquals('Expected value', $exception->getCustomThing());
$this->assertEquals(123, $exception->getCode());
}
);
// Test that a specific exception is NOT thrown
$this->assertNotThrows(MyException::class, function() use ($obj) {
$obj->doSomethingGood();
});
}
}
?>
public function testException() {
try {
$this->methodThatThrowsException();
$this->fail("Expected Exception has not been raised.");
} catch (Exception $ex) {
$this->assertEquals($ex->getMessage(), "Exception message");
}
}
assertEquals()
is assertEquals(mixed $expected, mixed $actual...)
,所以为反向,因此应该为$this->assertEquals("Exception message", $ex->getMessage());
这是您可以执行的所有异常断言。请注意,它们都是可选的。
class ExceptionTest extends PHPUnit_Framework_TestCase
{
public function testException()
{
// make your exception assertions
$this->expectException(InvalidArgumentException::class);
// if you use namespaces:
// $this->expectException('\Namespace\MyException');
$this->expectExceptionMessage('message');
$this->expectExceptionMessageRegExp('/essage$/');
$this->expectExceptionCode(123);
// code that throws an exception
throw new InvalidArgumentException('message', 123);
}
public function testAnotherException()
{
// repeat as needed
$this->expectException(Exception::class);
throw new Exception('Oh no!');
}
}
文档可以在这里找到。
/**
* @expectedException Exception
* @expectedExceptionMessage Amount has to be bigger then 0!
*/
public function testDepositNegative()
{
$this->account->deposit(-7);
}
注意"/**"
,请注意双“ *”。只写“ **”(星号)将使您的代码失败。还要确保您使用的是最新版本的phpUnit。在某些早期版本的phpunit中,@expectedException不支持异常。我有4.0,但它对我不起作用,我必须更新到5.5 https://coderwall.com/p/mklvdw/install-phpunit-with-composer才能使用composer进行更新。
对于PHPUnit 5.7.27和PHP 5.6并在一个测试中测试多个异常,强制进行异常测试很重要。如果没有异常发生,仅使用异常处理来声明Exception实例将跳过测试情况。
public function testSomeFunction() {
$e=null;
$targetClassObj= new TargetClass();
try {
$targetClassObj->doSomething();
} catch ( \Exception $e ) {
}
$this->assertInstanceOf(\Exception::class,$e);
$this->assertEquals('Some message',$e->getMessage());
$e=null;
try {
$targetClassObj->doSomethingElse();
} catch ( Exception $e ) {
}
$this->assertInstanceOf(\Exception::class,$e);
$this->assertEquals('Another message',$e->getMessage());
}
PhpUnit是一个了不起的库,但是这一点有点令人沮丧。这就是为什么我们可以使用turbotesting-php开源库的原因,该库具有非常方便的断言方法来帮助我们测试异常。在这里找到:
要使用它,我们只需执行以下操作:
AssertUtils::throwsException(function(){
// Some code that must throw an exception here
}, '/expected error message/');
如果我们在匿名函数中键入的代码未引发异常,则将引发异常。
如果我们在匿名函数中键入的代码引发异常,但其消息与预期的正则表达式不匹配,则也会引发异常。