Fra*_*mer 507
<?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);
}
}
Run Code Online (Sandbox Code Playgroud)
PHPUnit作者文章提供了有关测试异常最佳实践的详细说明.
Dav*_*ess 119
您还可以使用docblock注释:
class ExceptionTest extends PHPUnit_Framework_TestCase
{
/**
* @expectedException InvalidArgumentException
*/
public function testException()
{
...
}
}
Run Code Online (Sandbox Code Playgroud)
对于PHP 5.5+(特别是使用命名空间代码),我现在更喜欢使用 ::class
Jim*_*mix 42
太长了;滚动到:使用 PHPUnit 的数据提供程序
\nPHPUnit 9.5 提供了以下方法来测试异常:
\n$this->expectException(string $exceptionClassName);\n$this->expectExceptionCode(int|string $code);\n$this->expectExceptionMessage(string $message);\n$this->expectExceptionMessageMatches(string $regularExpression);\n$this->expectExceptionObject(\\Exception $exceptionObject);\nRun Code Online (Sandbox Code Playgroud)\n然而,文档对于测试代码中上述任何方法的顺序含糊其辞。
\n如果您习惯使用断言,例如:
\n<?php\n\nclass SimpleAssertionTest extends \\PHPUnit\\Framework\\TestCase\n{\n public function testSimpleAssertion(): void\n {\n $expected = \'bar\';\n $actual = \'bar\';\n $this->assertSame($expected, $actual);\n }\n}\nRun Code Online (Sandbox Code Playgroud)\n输出:
\n \xe2\x9c\x94 Simple assertion\nOK (1 test, 1 assertion)\nRun Code Online (Sandbox Code Playgroud)\n您可能会对异常测试失败感到惊讶:
\n<?php\n\nuse PHPUnit\\Framework\\TestCase;\n\nfinal class ExceptionTest extends TestCase\n{\n public function testException(): void\n {\n throw new \\InvalidArgumentException();\n $this->expectException(\\InvalidArgumentException::class);\n }\n}\nRun Code Online (Sandbox Code Playgroud)\n输出:
\n \xe2\x9c\x98 Exception\n \xe2\x94\x9c InvalidArgumentException:\n\nERRORS!\nTests: 1, Assertions: 0, Errors: 1.\nRun Code Online (Sandbox Code Playgroud)\n错误是因为:
\n\n\n一旦引发异常,PHP 就无法返回到引发异常的行之后的代码行。捕获异常在这方面没有任何改变。抛出异常是一张单程票。
\n
与错误不同,异常没有能力从中恢复并使 PHP 继续执行代码,就好像根本没有异常一样。
\n因此 PHPUnit 甚至没有到达这个地方:
\n \xe2\x9c\x98 Exception\n \xe2\x94\x9c InvalidArgumentException:\n\nERRORS!\nTests: 1, Assertions: 0, Errors: 1.\nRun Code Online (Sandbox Code Playgroud)\n如果它之前是:
\n$this->expectException(\\InvalidArgumentException::class);\nRun Code Online (Sandbox Code Playgroud)\n而且,无论 PHPUnit 有什么异常捕获能力,它都永远无法到达那个地方。
\n因此,使用 PHPUnit 的任何异常测试方法:
\nthrow new \\InvalidArgumentException();\nRun Code Online (Sandbox Code Playgroud)\n必须位于预期抛出异常的代码之前,这与设置实际值之后放置的断言相反。
\n使用异常测试的正确顺序:
\n$this->expectException(string $exceptionClassName);\n$this->expectExceptionCode(int|string $code);\n$this->expectExceptionMessage(string $message);\n$this->expectExceptionMessageMatches(string $regularExpression);\n$this->expectExceptionObject(\\Exception $exceptionObject);\nRun Code Online (Sandbox Code Playgroud)\n因为调用 PHPUnit 内部方法来测试异常必须在抛出异常之前,所以与测试异常相关的 PHPUnit 方法从 开始而$this->excpect不是开始是有意义的$this->assert。
已经知道:
\n\n\n一旦引发异常,PHP 就无法返回到引发异常的行之后的代码行。
\n
您应该能够轻松地在此测试中发现错误:
\n<?php\n\nuse PHPUnit\\Framework\\TestCase;\n\nfinal class ExceptionTest extends TestCase\n{\n public function testException(): void\n {\n $this->expectException(\\InvalidArgumentException::class);\n throw new \\InvalidArgumentException();\n }\n}\nRun Code Online (Sandbox Code Playgroud)\n第一个$this->expectException()应该没问题,它在抛出预期的确切异常类之前需要一个异常类,所以这里没有问题。
第二个应该失败的期望RuntimeException类在抛出完全不同的异常之前,所以它应该失败,但是 PHPUnit 执行会到达那个地方吗?
测试的输出是:
\n<?php\nnamespace VendorName\\PackageName;\n\nclass ExceptionTest extends \\PHPUnit\\Framework\\TestCase\n{\n public function testThrowException(): void\n {\n # Should be OK\n $this->expectException(\\RuntimeException::class);\n throw new \\RuntimeException();\n\n # Should Fail\n $this->expectException(\\RuntimeException::class);\n throw new \\InvalidArgumentException();\n }\n}\nRun Code Online (Sandbox Code Playgroud)\nOK?
OK不,测试距离通过还很远,并且应该Fail在第二个例外情况下通过。这是为什么?
请注意,输出有:
\n\n\nOK(1 个测试,1 个断言)
\n
其中测试计数是正确的,但只有1 assertion.
应该有 2 个断言 = OK,Fail这使得测试无法通过。
这只是因为 PHPUnittestThrowException在以下行之后执行完毕:
\xe2\x9c\x94 Throw exception\n\nOK (1 test, 1 assertion)\nRun Code Online (Sandbox Code Playgroud)\n这是一张单程票,超出testThrowException了 PHPUnit 捕获\\RuntimeException并执行其需要执行的操作的范围,但无论它能做什么,我们都知道它将无法跳回到testThrowException代码中:
throw new \\RuntimeException();\nRun Code Online (Sandbox Code Playgroud)\n永远不会被执行,这就是为什么从 PHPUnit 的角度来看测试结果是OK而不是Fail.
如果您想在同一测试方法中使用多个$this->expectException() 或混合使用$this->expectException()and调用,那么这不是一个好消息:$this->expectExceptionMessage()
# Should Fail\n$this->expectException(\\RuntimeException::class);\nthrow new \\InvalidArgumentException();\nRun Code Online (Sandbox Code Playgroud)\n给出错误:
\n\n\nOK(1 个测试,1 个断言)
\n
因为一旦抛出异常,$this->expect...与测试异常相关的所有其他调用将不会被执行,并且 PHPUnit 测试用例结果将仅包含第一个预期异常的结果。
<?php\nnamespace VendorName\\PackageName;\n\nclass ExceptionTest extends \\PHPUnit\\Framework\\TestCase\n{\n public function testThrowException(): void\n {\n # OK\n $this->expectException(\\RuntimeException::class);\n throw new \\RuntimeException(\'Something went wrong\');\n\n # Fail\n $this->expectExceptionMessage(\'This code will never be executed\');\n throw new \\RuntimeException(\'Something went wrong\');\n }\n}\nRun Code Online (Sandbox Code Playgroud)\n给出:
\n<?php\nnamespace VendorName\\PackageName;\n\nclass ExceptionTest extends \\PHPUnit\\Framework\\TestCase\n{\n public function testThrowExceptionBar(): void\n {\n # OK\n $this->expectException(\\RuntimeException::class);\n throw new \\RuntimeException();\n }\n\n public function testThrowExceptionFoo(): void\n {\n # Fail\n $this->expectException(\\RuntimeException::class);\n throw new \\InvalidArgumentException();\n }\n}\nRun Code Online (Sandbox Code Playgroud)\nFAILURES正如它应该。
然而,此方法在其基本方法上有一个缺点 - 对于抛出的每个异常,您都需要单独的测试。这将导致大量的测试只是为了检查异常。
\n如果在抛出异常后无法继续执行脚本,您可以简单地捕获预期的异常,然后使用异常提供的方法获取有关它的所有数据,并将其与预期值和断言结合使用:
\n \xe2\x9c\x94 Throw exception bar\n \xe2\x9c\x98 Throw exception foo\n \xe2\x94\x90\n \xe2\x94\x9c Failed asserting that exception of type "InvalidArgumentException" matches expected exception "RuntimeException". Message was: "" at\n\nFAILURES!\nTests: 2, Assertions: 2, Failures: 1.\nRun Code Online (Sandbox Code Playgroud)\n给出:
\n \xe2\x9c\x98 Throw exception\n \xe2\x94\x90\n \xe2\x94\x9c Failed asserting that two strings are identical.\n \xe2\x94\x8a ---\xc2\xb7Expected\n \xe2\x94\x8a +++\xc2\xb7Actual\n \xe2\x94\x8a @@ @@\n \xe2\x94\x8a -\'Something\xc2\xb7went\xc2\xb7wrong\'\n \xe2\x94\x8a +\'I\xc2\xb7MUST\xc2\xb7FAIL\xc2\xb7!\'\n\nFAILURES!\nTests: 1, Assertions: 5, Failures: 1.\nRun Code Online (Sandbox Code Playgroud)\nFAILURES应该如此,但是天哪,您读过上面的内容了吗?您需要注意清除变量unset($className);以检测是否引发了异常,然后该生物$location = __FILE__ ...拥有异常的精确位置(以防未引发异常),然后检查是否引发了异常if (empty($className)) { ... }并使用$this->fail($failMsg);并在未引发异常时信号发出信号抛出。
PHPUnit 有一个有用的机制,称为数据提供程序。数据提供者是一种返回带有数据集的数据(数组)的方法。testThrowException 当PHPUnit 调用测试方法时,单个数据集用作参数。
如果数据提供者返回多个数据集,则测试方法将运行多次,每次都使用另一个数据集。这在测试多个异常或/和多个异常的属性(如类名、消息、代码)时很有帮助,因为即使:
\n\n\n一旦引发异常,PHP 就无法返回到引发异常的行之后的代码行。
\n
PHPUnit 将多次运行测试方法,每次都使用不同的数据集,因此不会在单个测试方法运行中测试多个异常(这将失败)。
\n这就是为什么我们可以让一个测试方法负责一次只测试一个异常,但通过使用 PHPUnit 的数据提供程序使用不同的输入数据和预期异常多次运行该测试方法。
\n@dataProvider数据提供者方法的定义可以通过对应该由数据提供者使用数据集提供的测试方法进行注释来完成。
<?php\nnamespace VendorName\\PackageName;\n\nclass ExceptionTest extends \\PHPUnit\\Framework\\TestCase\n{\n public function testThrowException(): void\n {\n # OK\n unset($className);\n try {\n $location = __FILE__ . \':\' . (string) (__LINE__ + 1);\n throw new \\RuntimeException(\'Something went wrong\'); \n\n } catch (\\Exception $e) {\n $className = get_class($e);\n $msg = $e->getMessage();\n $code = $e->getCode();\n }\n\n $expectedClass = \\RuntimeException::class;\n $expectedMsg = \'Something went wrong\';\n $expectedCode = 0;\n\n if (empty($className)) {\n $failMsg = \'Exception: \' . $expectedClass;\n $failMsg .= \' with msg: \' . $expectedMsg;\n $failMsg .= \' and code: \' . $expectedCode;\n $failMsg .= \' at: \' . $location;\n $failMsg .= \' Not Thrown!\';\n $this->fail($failMsg);\n }\n\n $this->assertSame($expectedClass, $className);\n $this->assertSame($expectedMsg, $msg);\n $this->assertSame($expectedCode, $code);\n\n # ------------------------------------------\n\n # Fail\n unset($className);\n try {\n $location = __FILE__ . \':\' . (string) (__LINE__ + 1);\n throw new \\InvalidArgumentException(\'I MUST FAIL !\'); \n\n } catch (\\Exception $e) {\n $className = get_class($e);\n $msg = $e->getMessage();\n $code = $e->getCode();\n }\n\n $expectedClass = \\InvalidArgumentException::class;\n $expectedMsg = \'Something went wrong\';\n $expectedCode = 0;\n\n if (empty($className)) {\n $failMsg = \'Exception: \' . $expectedClass;\n $failMsg .= \' with msg: \' . $expectedMsg;\n $failMsg .= \' and code: \' . $expectedCode;\n $failMsg .= \' at: \' . $location;\n $failMsg .= \' Not Thrown!\';\n $this->fail($failMsg);\n }\n\n $this->assertSame($expectedClass, $className);\n $this->assertSame($expectedMsg, $msg);\n $this->assertSame($expectedCode, $code);\n }\n}\nRun Code Online (Sandbox Code Playgroud)\n给出结果:
\n \xe2\x9c\x98 Throw exception\n \xe2\x94\x90\n \xe2\x94\x9c Failed asserting that two strings are identical.\n \xe2\x94\x8a ---\xc2\xb7Expected\n \xe2\x94\x8a +++\xc2\xb7Actual\n \xe2\x94\x8a @@ @@\n \xe2\x94\x8a -\'Something\xc2\xb7went\xc2\xb7wrong\'\n \xe2\x94\x8a +\'I\xc2\xb7MUST\xc2\xb7FAIL\xc2\xb7!\'\n\nFAILURES!\nTests: 1, Assertions: 5, Failures: 1.\nRun Code Online (Sandbox Code Playgroud)\nExceptionTest请注意,即使整个PHPUnit 的输出中只有一个测试方法,其输出也是:
\n\n好的(2 个测试,2 个断言)
\n
所以即使是这一行:
\n<?php\n\nclass ExceptionCheck\n{\n public function throwE($data)\n {\n if ($data === 1) {\n throw new \\RuntimeException;\n } else {\n throw new \\InvalidArgumentException;\n }\n }\n}\n\nclass ExceptionTest extends \\PHPUnit\\Framework\\TestCase\n{\n public function ExceptionTestProvider() : array\n {\n $data = [\n \\RuntimeException::class =>\n [\n [\n \'input\' => 1,\n \'className\' => \\RuntimeException::class\n ]\n ],\n\n \\InvalidArgumentException::class =>\n [\n [\n \'input\' => 2,\n \'className\' => \\InvalidArgumentException::class\n ]\n ]\n ];\n return $data;\n }\n\n /**\n * @dataProvider ExceptionTestProvider\n */\n public function testThrowException($data): void\n {\n $this->expectException($data[\'className\']);\n $exceptionCheck = new ExceptionCheck;\n\n $exceptionCheck->throwE($data[\'input\']);\n }\n}\nRun Code Online (Sandbox Code Playgroud)\n第一次抛出异常,使用相同的测试方法测试另一个异常没有问题,因为由于数据提供者,PHPUnit 使用不同的数据集再次运行了它。
\n数据提供者返回的每个数据集都可以命名,您只需要使用一个字符串作为存储数据集的键即可。因此预期的异常类名被使用了两次。作为数据集数组的键和稍后用作 的参数的值(在“className”键下)$this->expectException()。
使用字符串作为数据集的键名称可以使总结变得漂亮且不言自明:
\n\n\n\xe2\x9c\x94 使用RuntimeException抛出异常
\n\xe2\x9c\x94 使用InvalidArgumentException抛出异常
\n
如果你改变线路:
\n \xe2\x9c\x94 Throw exception with RuntimeException\n \xe2\x9c\x94 Throw exception with InvalidArgumentException\n\nOK (2 tests, 2 assertions)\nRun Code Online (Sandbox Code Playgroud)\n到:
\nif ($data !== 1) {\nRun Code Online (Sandbox Code Playgroud)\n的public function throwE($data)
要抛出错误的异常并再次运行 PHPUnit,您将看到:
\n \xe2\x9c\x98 Throw exception with RuntimeException\n \xe2\x94\x9c Failed asserting that exception of type "InvalidArgumentException" matches expected exception "RuntimeException". Message was: "" at (...)\n\n \xe2\x9c\x98 Throw exception with InvalidArgumentException\n \xe2\x94\x9c Failed asserting that exception of type "RuntimeException" matches expected exception "InvalidArgumentException". Message was: "" at (...)\n\nFAILURES!\nTests: 2, Assertions: 2, Failures: 2.\nRun Code Online (Sandbox Code Playgroud)\n正如预期:
\n\n\n失败!\n测试:2,断言:2,失败:2。
\n
准确指出了导致一些问题的数据集名称:
\n\n\n\xe2\x9c\x98 使用RuntimeException抛出异常
\n\xe2\x9c\x98 使用InvalidArgumentException抛出异常
\n
制作 public function throwE($data)抛出任何异常:
$exceptionCheck->throwE($data[\'input\']);\nRun Code Online (Sandbox Code Playgroud)\n再次运行 PHPUnit 给出:
\nif ($data === 1) {\nRun Code Online (Sandbox Code Playgroud)\n看起来使用数据提供者有几个优点:
\nPHP7 数据类型支持此测试:
\nif ($data !== 1) {\nRun Code Online (Sandbox Code Playgroud)\n失败并输出:
\n \xe2\x9c\x98 Say\n \xe2\x94\x9c Failed asserting that exception of type "TypeError" matches expected exception "InvalidArgumentException". Message was: "Argument 1 passed to DatatypeChat::say() must be of the type string, array given (..)\n\nFAILURES!\nTests: 1, Assertions: 1, Failures: 1.\nRun Code Online (Sandbox Code Playgroud)\n即使方法中有say:
\xe2\x9c\x98 Throw exception with RuntimeException\n \xe2\x94\x9c Failed asserting that exception of type "InvalidArgumentException" matches expected exception "RuntimeException". Message was: "" at (...)\n\n \xe2\x9c\x98 Throw exception with InvalidArgumentException\n \xe2\x94\x9c Failed asserting that exception of type "RuntimeException" matches expected exception "InvalidArgumentException". Message was: "" at (...)\n\nFAILURES!\nTests: 2, Assertions: 2, Failures: 2.\nRun Code Online (Sandbox Code Playgroud)\n并且测试传递了一个数组而不是一个字符串:
\npublic function throwE($data)\n{\n}\nRun Code Online (Sandbox Code Playgroud)\nPHP 未到达代码:
\n \xe2\x9c\x98 Throw exception with RuntimeException\n \xe2\x94\x9c Failed asserting that exception of type "RuntimeException" is thrown.\n\n \xe2\x9c\x98 Throw exception with InvalidArgumentException\n \xe2\x94\x9c Failed asserting that exception of type "InvalidArgumentException" is thrown.\n\nFAILURES!\nTests: 2, Assertions: 2, Failures: 2.\nRun Code Online (Sandbox Code Playgroud)\n因为由于类型输入而提前引发了异常string:
<?php\ndeclare(strict_types=1);\n\nclass DatatypeChat\n{\n public function say(string $msg)\n {\n if (!is_string($msg)) {\n throw new \\InvalidArgumentException(\'Message must be a string\');\n }\n return "Hello $msg";\n }\n}\n\nclass ExceptionTest extends \\PHPUnit\\Framework\\TestCase\n{\n public function testSay(): void\n {\n $this->expectException(\\InvalidArgumentException::class);\n $chat = new DatatypeChat;\n $chat->say(array());\n }\n}\nRun Code Online (Sandbox Code Playgroud)\n因此 被 TypeError抛出而不是InvalidArgumentException
知道我们不需要if (!is_string($msg))检查数据类型,因为 PHP 已经注意到,如果我们在方法声明中指定数据类型,如果消息太长,say(string $msg)我们可能想要抛出 异常。InvalidArgumentExceptionif (strlen($msg) > 3)
\xe2\x9c\x98 Say\n \xe2\x94\x9c Failed asserting that exception of type "TypeError" matches expected exception "InvalidArgumentException". Message was: "Argument 1 passed to DatatypeChat::say() must be of the type string, array given (..)\n\nFAILURES!\nTests: 1, Assertions: 1, Failures: 1.\nRun Code Online (Sandbox Code Playgroud)\n还进行修改,ExceptionTest因此我们有两种情况(测试方法)Exception应该抛出异常 - 第一种testSayTooLong是当消息太长时,第二种testSayDataType是当消息类型错误时。
在这两个测试中,我们期望使用以下方法来代替特定的异常类(例如InvalidArgumentException通用TypeError类)Exception
$this->expectException(\\Exception::class);
测试结果是:
\nif (!is_string($msg)) {\n throw new \\InvalidArgumentException(\'Message must be a string\');\n}\nRun Code Online (Sandbox Code Playgroud)\ntestSayTooLong()期待通用Exception并使用
$this->expectException(\\Exception::class);
OK当 被InvalidArgumentException抛出时通过
但
\ntestSayDataType()$this->expectException(\\Exception::class); Fails使用与描述相同的内容:
\n\n无法断言“ TypeError ”类型的异常与预期的异常“ Exception ”匹配。
\n
PHPUnit 抱怨异常 TypeError不是 an ,这看起来很令人困惑,否则它在 内部Exception不会有任何问题,因为它在抛出和期望方面没有任何问题:$this->expectException(\\Exception::class);testSayDataType()testSayTooLong()InvalidArgumentException$this->expectException(\\Exception::class);
问题在于 PHPUnit 的上述描述会误导您,因为 PHPUnit并不TypeError例外。不延伸自TypeErrorException或其任何其他子类延伸。
TypeError实现Throwable 接口见文档
然而
\nInvalidArgumentException扩展LogicException 文档
并LogicException扩展Exception 文档
从而也InvalidArgumentException延伸。Exception
这就是为什么InvalidArgumentException用 OK 抛出通过测试,$this->expectException(\\Exception::class);但抛出 TypeError不会(它不会扩展Exception)
Dav*_*ess 34
如果您在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');
}
}
Run Code Online (Sandbox Code Playgroud)
PHP编译
WrongPasswordException::class
Run Code Online (Sandbox Code Playgroud)
成
"\My\Cool\Package\WrongPasswordException"
Run Code Online (Sandbox Code Playgroud)
没有PHPUnit是更明智的.
注意:PHPUnit 5.2
expectException作为替代品引入setExpectedException.
Far*_*mov 29
下面的代码将测试异常消息和异常代码.
重要提示:如果没有抛出预期的异常,它将失败.
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());
}
Run Code Online (Sandbox Code Playgroud)
hej*_*dav 23
您可以使用assertException扩展在一次测试执行期间声明多个异常.
将方法插入TestCase并使用:
public function testSomething()
{
$test = function() {
// some code that has to throw an exception
};
$this->assertException( $test, 'InvalidArgumentException', 100, 'expected message' );
}
Run Code Online (Sandbox Code Playgroud)
我也为漂亮的代码爱好者做了一个特质.
小智 14
另一种方法可以是:
$this->expectException(\InvalidArgumentException::class);
$this->expectExceptionMessage('Expected Exception Message');
Run Code Online (Sandbox Code Playgroud)
请确保您的测试类范围\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');
}
Run Code Online (Sandbox Code Playgroud)
将它添加到您的测试类并以这种方式调用:
public function testSomething() {
$this->assertException(\PDOException::class, function() {
new \PDO('bad:param');
});
$this->assertException(\PDOException::class, function() {
new \PDO('foo:bar');
});
}
Run Code Online (Sandbox Code Playgroud)
小智 8
public function testException() {
try {
$this->methodThatThrowsException();
$this->fail("Expected Exception has not been raised.");
} catch (Exception $ex) {
$this->assertEquals($ex->getMessage(), "Exception message");
}
}
Run Code Online (Sandbox Code Playgroud)
PHPUnit目前用于异常测试的" 最佳实践 "似乎......乏味(docs).
由于我强烈反对当前的expectException实现,我在我的测试用例中使用了一个特性.它只有50行.
assert语法assertNotThrows我将这个Throwable特性发布给了Github和packagist,所以它可以和作曲家一起安装.
只是为了说明语法背后的精神:
<?php
// Using simple callback
$this->assertThrows(MyException::class, [$obj, 'doSomethingBad']);
// Using anonymous function
$this->assertThrows(MyException::class, function() use ($obj) {
$obj->doSomethingBad();
});
Run Code Online (Sandbox Code Playgroud)
很简约?
请参阅下面的更全面的用法示例:
<?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();
});
}
}
?>
Run Code Online (Sandbox Code Playgroud)
这是您可以执行的所有异常断言。请注意,它们都是可选的。
class ExceptionTest extends PHPUnit_Framework_TestCase
{
public function testException()
{
// make your exception assertions
$this->expectException(InvalidArgumentException::class);
// if you use namespaces:
// $this->expectException('\Namespace\MyExceptio??n');
$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!');
}
}
Run Code Online (Sandbox Code Playgroud)
文档可以在这里找到。