pitchart / phlunit
Fluent assertions for PHP
Requires
- justinrainbow/json-schema: ^5.2
- openlss/lib-array2xml: ^1.0
- phpcollection/phpcollection: ^0.5.0
- phpunit/phpunit: ~8.5 || ^9
- pitchart/transformer: ^1.6
- psr/http-message: ^1.0
Requires (Dev)
- friendsofphp/php-cs-fixer: ^2.18
- guzzlehttp/psr7: ^1.7
- vimeo/psalm: 4.4
This package is auto-updated.
Last update: 2024-10-13 17:32:04 UTC
README
Phlunit: PHP Fluent Unit Testing
Check::that(tdd())->with($phlunit)->isAnInstanceOf(Awesomeness::class);
Fluent assertions for phpunit.
Why ?
Phlunit
will make your tests:
- fluent to write: juste type
Check::that($sut)
and let auto-completion guide you. - fluent to read: very close to plain English, making it easier for non-technical people to read test code.
- fluent to troubleshoot: every failing check throws an Exception with a clear message status to ease your TDD experience.
- less error-prone: no more confusion about the order of the "expected" and "actual" values.
Installation
composer require --dev pitchart/phlunit
Write checks
Write test cases and test methods as usual, just switch to Check::that()
to write your assertions :
use Pitchart\Phlunit\Check; $integers = [1, 2, 3, 4, 5, 42]; Check::that($integers)->contains(2, 3, 42); $heroes = "Batman and Robin"; Check::that($heroes) ->startsWith("Batman") ->contains("Robin") ; // Collection checks Check::that([0, 1, 2]) ->isACollectionOf('integer') ->hasElementAt(1) ->and->hasNoElementAt(12) ->hasLength(3) ->hasNotLength(12) ->contains(1, 2) ->isSubsetOf(0, 1, 2, 3, 4) ->containsNoDuplicateItem() ; // PSR-7 ResponseInterface checks $response = (new Response(200)) ->withHeader('xxx-header', 'xxx-header-value') ->withBody(Utils::streamFor('{"name": "Batman", "city": "Gotham City"}')) ; Check::that($response) ->asJson() ->matchesSchema(['type' => 'object', 'required' => ['name'], 'properties' => ['name' => ['type' => 'string']]]);
Phlunit
provides checks for the following types and classes :
- string, boolean, integer, float, array
- xml and json formats
- iterable
- callable
- Throwable
- ResponseInterface (PSR-7)
- DateTimeInterface
Syntactic sugar
Improve readability using that()
and andThat()
methods :
Check::thatCall([$spiderman, 'saveGotham'])->with('batman', 'superman') ->throws(\LogicException::class) ->that()->isDescribedBy("Sorry, we are not in the same univers!"); Check::that($batman->getFirstname())->isEqualTo('Bruce') ->andThat($batman->getLastname())->isEqualTo('Wayne');
Need more checks ?
Use custom constraints
Write custom phpunit constraints and use them thanks to methods is()
, has()
, isNot()
or hasNot()
:
class CustomConstraint extends Constraint { //... } Check::that($sut)->is(new CustomConstraint());
Create custom Check class
class CustomClassCheck implements FluentCheck { //... } // Register your custom checks for dedicated classes in phpunit's bootstrap file Check::registerChecksFor(Custom::class, CustomClassChecks::class); // Check::that(Check::that(new Custom))->isAnInstanceOf(CustomClassChecks::class);
Test data builder
Phlunit
provides a simple and extensible way to implement the test data builder pattern.
Here is the recommended way to use it, to not break the fluent experience:
use Pitchart\Phlunit\Builder; class HeroBuilder extends Builder { protected function __construct(array $arguments) { parent::__construct(Hero::class, $arguments); } public function build(): Hero { return $this->buildInstance(); } public static function create(): self { return new self([ 'name' => 'Batman', 'firstname' => 'Bruce', 'lastname' => 'Wayne', ]); } public static function batman(): self { return self::create(); } } // Use it in your test cases: $batman = HeroBuilder::batman()->build(); $superman = HeroBuilder::create() ->withName('Superman') ->andFirstname('Clark') ->andLastname('Kent') ->build() ;
Expect exceptions
Phlunit
provides a fluent way to expect exception from your code, using the Expect
class:
use Pitchart\Phlunit\Expect; public function test_an_exception_is_thrown() { Expect::after($this) ->anException(\InvalidArgumentException) ->describedBy('An exception message') ->havingCode(42); // Act }
Credits
This package has been mainly inspired by NFluent and AssertJ
Thanks to Bruno Boucard for the inspiration.
Licence
The MIT Licence