phrozenbyte / phpunit-throwable-asserts
提供各种与Throwable相关的PHPUnit断言。
Requires
- php: ^7.2 || ^8.0
Requires (Dev)
- incompass/coverage: ^1.0
- mockery/mockery: ^1.3
- php-parallel-lint/php-parallel-lint: ^1.2
- phpunit/phpunit: ^8
- psalm/plugin-mockery: ^0.7.0
- psalm/plugin-phpunit: ^0.15.1
- symfony/yaml: ^4.4
- vimeo/psalm: ^4.5
Conflicts
- phpunit/phpunit: <8.0
This package is auto-updated.
Last update: 2024-09-16 01:42:48 UTC
README
PHPUnitThrowableAssertions
是一个小的 PHPUnit 扩展,用于断言可调用对象是否抛出特定的异常、错误或Throwable。
这个PHPUnit扩展允许开发者使用更直观的“断言为”方法,在单个断言中测试可调用对象是否抛出异常、错误和其他Throwable。它是PHPUnit内置的 expectException()
、expectExceptionMessage()
和 expectExceptionCode()
方法的替代品,但功能更强大。
你需要更多PHPUnit约束?查看 PHPUnitArrayAssertions
!它引入了各种断言,可以在单个断言中测试PHP数组和类似数组的数组数据。PHPUnit扩展通常用于API测试,用于断言API结果是否符合某些标准——包括其结构和数据。
由 Daniel Rudolf 制作。 PHPUnitThrowableAssertions
是免费和开源软件,根据 MIT许可证 发布。
目录
安装
PHPUnitThrowableAssertions
可在 Packagist.org 上找到,并可以使用 Composer 进行安装
composer require --dev phrozenbyte/phpunit-throwable-asserts
此PHPUnit扩展最初是为PHPUnit 8编写的,但应与任何后续的PHPUnit版本兼容。如果不兼容,请勿犹豫,在GitHub上打开一个 新问题,或者,更好的是,创建一个包含建议修复的Pull Request。
使用方法
使用 PHPUnitThrowableAssertions
有三种(等效的)方法
- 通过使用静态 类
PhrozenByte\PHPUnitThrowableAssertions\Assert
- 通过在您的测试用例中使用 特质
PhrozenByte\PHPUnitThrowableAssertions\ThrowableAssertsTrait
- 通过创建新的 约束实例 (
PhrozenByte\PHPUnitThrowableAssertions\Constraint\…
)
所有选项都完全相同。创建新的约束实例对于高级断言很有用,例如与 PHPUnit\Framework\Constraint\LogicalAnd
一起使用。
如果您想向您的可调用对象传递参数,您可能想使用 CallableProxy
。如果您想访问可调用对象的返回值或可能抛出的Throwable,请使用 CachedCallableProxy
(特别是其 getReturnValue()
和 getThrowable()
方法)。使用 CallableProxy
可以大大改进错误处理。
如上所述,PHPUnitThrowableAssertions
是 PHPUnit 内置的 expectException()
的更强大替代方案。然而,请注意,PHPUnit 内置的 expectExceptionMessage()
匹配子字符串(即 $this->expectExceptionMessage('test')
不仅匹配消息 "test"
,还匹配 "This is a test"
),而 PHPUnitThrowableAssertions
默认通过相等性进行检查(即 $message = 'test'
只匹配消息 "test"
)。但是,PHPUnitThrowableAssertions
允许您不仅使用字符串,还可以使用任意约束。因此,例如,为了实现子字符串匹配,请传递一个 PHPUnit\Framework\Constraint\StringContains
约束的实例(即 $message = $this->stringContains('test')
也匹配消息 "This is a test"
)。
约束 CallableThrows
CallableThrows
约束断言一个 Callable 抛出一个特定的 Throwable
。
该约束调用给定的 Callable(参数 $callable
)并捕获与给定基类(参数 $throwableBaseClassName
,默认为 Throwable
)匹配的任何 Throwable
。任何其他 Throwable
都不会被捕获。然后它断言 Throwable
的类(可选参数 $throwableClassName
,默认为 Throwable
)、消息(可选参数 $throwableMessage
,默认为 null
)和代码(可选参数 $throwableCode
,默认为 null
)与预期匹配,否则抛出 ExpectationFailedException
。异常消息可以是字符串,需要精确匹配,也可以是任意 Constraint
(例如 PHPUnit\Framework\Constraint\StringContains
)以匹配异常消息。约束可选地需要类名的精确匹配(可选参数 $throwableExactMatch
,默认为 false
)。
ThrowableAssertsTrait
特性公开了两个公共方法用于 CallableThrows
约束:使用 ThrowableAssertsTrait::assertCallableThrows()
进行断言,并使用 ThrowableAssertsTrait::callableThrows()
创建 CallableThrows
约束的新实例。
使用方法
// using `PhrozenByte\PHPUnitThrowableAsserts\ThrowableAssertsTrait` trait ThrowableAssertsTrait::assertCallableThrows( callable $callable, // the Callable to call string $throwableClassName = Throwable::class, // assert that a Throwable of the given class is thrown Constraint|string $throwableMessage = null, // assert that its message matches the given constraint int|string $throwableCode = null, // assert that its code matches the given one bool $throwableExactMatch = false, // whether an exact match of the class name is required string $throwableBaseClassName = Throwable::class, // catch all Throwables of the given class string $message = '' // additional information about the test ); // using new instance of `PhrozenByte\PHPUnitThrowableAsserts\Constraint\CallableThrows` new CallableThrows( string $className = Throwable::class, Constraint|string $message = null, int|string $code = null, bool $exactMatch = false, string $baseClassName = Throwable::class );
示例
$controller = new BookController(); $bookName = "The Hitchhiker's Guide to the Galaxy"; $bookReleaseDate = '1979-10-12'; $this->assertCallableThrows( $this->callableProxy([ $controller, 'create' ], $bookName, $bookReleaseDate), BookAlreadyExistsException::class, 'Unable to create book: Book already exists' );
调试
$service = new HitchhikersGuideService(); $towel = false; $answer = 42; $this->assertCallableThrows( static function () use ($service, $towel, $answer) { $service->checkAnswer($answer); // throws a OpaqueAnswerException $service->checkTowel($towel); // throws a PanicException (unreachable code) }, PanicException::class, 'I forgot my towel' ); // Will fail with the following message: // // Failed asserting that {closure}() throws a PanicException whose message is 'Time to panic'. // Encountered invalid OpaqueAnswerException: I do not understand. // --- Expected // +++ Actual // @@ @@ // -'Time to panic' // +'I do not understand'
约束 CallableThrowsNot
CallableThrowsNot
约束断言一个 Callable 不抛出特定的 Throwable
。它可以作为 PHPUnit 内置的 expectNotToPerformAssertions()
方法的更具体替代方案。
该约束调用给定的 Callable(参数 $callable
)并捕获与给定类(可选参数 $throwableClassName
,默认为 Throwable
)、消息(可选参数 $throwableMessage
,默认为 null
)和代码(可选参数 $throwableCode
,默认为 null
)匹配的任何 Throwable
。所有条件都必须匹配,否则将重新抛出 Throwable
。异常消息可以是字符串,需要精确匹配,也可以是任意 Constraint
(例如 PHPUnit\Framework\Constraint\StringContains
)以匹配异常消息。约束可选地需要类名的精确匹配(可选参数 $throwableExactMatch
,默认为 false
)。
这 不 与否定 CallableThrows
约束相同,后者消费所有不匹配的 Throwable
并抛出 ExpectationFailedException
。CallableThrowsNot
将重新抛出任何不匹配的 Throwable
。只有在 Callable 抛出匹配所有给定条件的 Throwable
时才会抛出 ExpectationFailedException
。
ThrowableAssertsTrait
特性公开了两个公共方法用于 CallableThrowsNot
约束:使用 ThrowableAssertsTrait::assertCallableThrowsNot()
进行断言,并使用 ThrowableAssertsTrait::callableThrowsNot()
创建 CallableThrowsNot
约束的新实例。
使用方法
// using `PhrozenByte\PHPUnitThrowableAsserts\ThrowableAssertsTrait` trait ThrowableAssertsTrait::assertCallableThrowsNot( callable $callable, // the Callable to call string $throwableClassName = Throwable::class, // assert that no Throwable of the given class is thrown Constraint|string $throwableMessage = null, // catch Throwables matching the given message constraint only int|string $throwableCode = null, // catch Throwables matching the given code only bool $throwableExactMatch = false, // whether only Throwables of the given class are caught string $message = '' // additional information about the test ); // using new instance of `PhrozenByte\PHPUnitThrowableAsserts\Constraint\CallableThrowsNot` new CallableThrowsNot( string $className = Throwable::class, Constraint|string $message = null, int|string $code = null, bool $exactMatch = false );
示例
$controller = CharacterController(); $character = 'Prostetnik Vogon Jeltz'; $this->assertCallableThrowsNot( $this->callableProxy([ $controller, 'meet' ], $character), VogonWantsToReadPoetException::class );
调试
$controller = new BookController(); $bookName = "The Hitchhiker's Guide to the Galaxy"; $bookReleaseDate = '1979-10-12'; $this->assertCallableThrowsNot( $this->callableProxy([ $controller, 'create' ], $bookName, $bookReleaseDate), BookAlreadyExistsException::class ); // Will fail with the following message: // // Failed asserting that BookController::create() does not throw a BookAlreadyExistsException // Encountered invalid BookAlreadyExistsException: Unable to create book: Book already exists
CallableProxy
和 CachedCallableProxy
PHPUnitThrowableAsserts
在调用可调用对象(Callable)时不需要参数,并且由于PHPUnit如何评估值,因此会丢弃可能的返回值。针对此问题的一个解决方案是使用具有变量继承的匿名函数。作为一个简洁的替代方案,PHPUnitThrowableAsserts
提供了CallableProxy
和 CachedCallableProxy
辅助类。
这两个辅助类在其构造函数中接收要调用的可调用对象(参数 $callable
)和要传递的参数(任何后续参数,变长参数 $arguments
)。此外,它们还实现了PHPUnit的 PHPUnit\Framework\SelfDescribing
接口和 toString()
方法,通过允许 PHPUnitThrowableAsserts
更好地指定调用方法,从而提高了错误处理能力。CachedCallableProxy
还实现了 getReturnValue()
和 getThrowable()
方法。getReturnValue()
返回可调用对象上次调用的缓存返回值,而 getThrowable()
返回可能抛出的 Throwable
。
ThrowableAssertsTrait
特性公开了两个公共方法来创建 CallableProxy
和 CachedCallableProxy
的实例:使用 ThrowableAssertsTrait::callableProxy()
创建一个新的 CallableProxy
实例,或者使用 ThrowableAssertsTrait::cachedCallableProxy()
创建一个新的 CachedCallableProxy
实例。
使用方法
// create new instance of `PhrozenByte\PHPUnitThrowableAsserts\CallableProxy` // using the `PhrozenByte\PHPUnitThrowableAsserts\ThrowableAssertsTrait` trait ThrowableAssertsTrait::callableProxy( callable $callable, // the Callable to invoke mixed ...$arguments // the arguments to pass to the Callable ); // create new instance of `PhrozenByte\PHPUnitThrowableAsserts\CachedCallableProxy` // using the `PhrozenByte\PHPUnitThrowableAsserts\ThrowableAssertsTrait` trait $proxy = ThrowableAssertsTrait::cachedCallableProxy( callable $callable, // the Callable to invoke mixed ...$arguments // the arguments to pass to the Callable ); // get return value of the Callable (`CachedCallableProxy` only) $proxy->getReturnValue(); // get a possibly thrown Throwable (`CachedCallableProxy` only) $proxy->getThrowable();
示例
$computer = new DeepThought(); $question = 'What is the Answer to the Ultimate Question of Life, the Universe, and Everything?'; // using `PhrozenByte\PHPUnitThrowableAsserts\CallableProxy` // if the assertion fails, `ExpectationFailedException`'s message will point to DeepThought::ask() as source $askQuestion = $this->cachedCallableProxy([ $computer, 'ask' ], $question); $this->assertCallableThrowsNot($askQuestion); $answer = $askQuestion->getReturnValue(); // using anonymous function // if the assertion fails, `ExpectationFailedException` will just name {closure} as source $answer = null; $this->assertCallableThrowsNot(static function () use ($computer, $question, &$answer) { // use variable reference to pass the return value $answer = $computer->ask($question); });
PHP错误、警告和通知
PHPUnit 默认将 PHP 错误(E_RECOVERABLE_ERROR
)、警告(E_WARNING
和 E_USER_WARNING
)、通知(E_NOTICE
、E_USER_NOTICE
和 E_STRICT
)和弃用通知(E_DEPRECATED
和 E_USER_DEPRECATED
)转换为 PHPUnit\Framework\Error\…
异常(分别为 …\Error
、…\Warning
、…\Notice
和 …\Deprecated
)。这使得您可以使用 PHPUnitThrowableAssertions
的 assertCallableThrows()
和 assertCallableThrowsNot()
断言来捕获任何PHP错误;只需使用 PHPUnit\Framework\Error\…
中的一个类即可。
请勿将PHP错误与PHP 7.0中引入的 Error
类 混淆。后者已经是一个 Throwable
,并且可以像往常一样捕获。
示例
$this->assertCallableThrows( static function () { // triggers a E_NOTICE PHP error echo $undefinedVariable; }, \PHPUnit\Framework\Error\Notice::class, 'Undefined variable: undefinedVariable' );