On Github austinsmorris / extending-peridot
Customize your testing platform with events, plugins, reporters, scopes, and more!
Austin Morris / @austinsmorris Slides: https://austinsmorris.github.io/extending-peridot
<?php describe('A thing', function () { // I am a suite! beforeEach(function () { // Somebody set up us the bomb! }); it('should do a thing', function () { // I am a test! }); // more it()... afterEach(function () { // Tear down! }); });
describe('A thing', function () { beforeEach(function () { // Somebody set up us the bomb! }); context('in this context', function () { // I am another suite! beforeEach(function () { // I only run in this context }); it('should do a very specific thing', function () { // Both beforeEach() functions were executed before me! }); }); });
"The Console component eases the creation of beautiful and testable command line interfaces."
Abstractions for:
Configure your PHP tests with PHP!
Even this is configurable:
$ vendor/bin/peridot -c foo/bar.php
$ vendor/bin/peridot --configuration foo/bar.php
<?php use Evenement\EventEmitterInterface; /** * Configure peridot. * * @param EventEmitterInterface $eventEmitter */ return function (EventEmitterInterface $eventEmitter) { // Everything that is cool and rad goes here! };
Peridot has a single application event manager driving and providing access to the entire testing lifecyle.
Événementinterface EventEmitterInterface { public function on($event, callable $listener); public function once($event, callable $listener); public function removeListener($event, callable $listener); public function removeAllListeners($event = null); public function listeners($event); public function emit($event, array $arguments = []); }
Set the default path:
use Evenement\EventEmitterInterface; use Peridot\Console\Environment; return function (EventEmitterInterface $eventEmitter) { $eventEmitter->on('peridot.start', function (Environment $environment) { $environment->getDefinition()->getArgument('path')->setDefault('specs'); }); };
use Evenement\EventEmitterInterface; use Peridot\Core\Test; return function (EventEmitterInterface $eventEmitter) { $eventEmitter->on('test.passed', function (Test $test) use ($eventEmitter) { $eventEmitter->emit('wackyEvent', [$test]); }); $eventEmitter->on('wackyEvent', function (Test $test) { // do something wacky! }); };
class MyPlugin { protected $emitter; public function __construct(EventEmitterInterface $emitter) { $this->emitter = $emitter; $this->listen(); } protected function listen() { $this->emitter->on('suite.start', [$this, 'onSuiteStart']); } public function onSuiteStart(Suite $suite) { // do something when a suite starts } }
use Evenement\EventEmitterInterface; return function (EventEmitterInterface $eventEmitter) { new MyPlugin($eventEmitter); };
use Evenement\EventEmitterInterface; use Peridot\Plugin\Yo\YoPlugin; return function (EventEmitterInterface $emitter) { $yoPlugin = YoPlugin::register( $emitter, "your-yo-token", ['USER1', 'USER2'], 'http://linktobuild.com' ); $yoPlugin->setBehavior(YoPlugin::BEHAVIOR_ON_FAIL); };
use Evenement\EventEmitterInterface; use Peridot\Plugin\Watcher\WatcherPlugin; return function(EventEmitterInterface $emitter) { $watcher = new WatcherPlugin($emitter); $watcher->track(__DIR__ . '/src'); };
use Evenement\EventEmitterInterface; use Peridot\Concurrency\ConcurrencyPlugin; return function (EventEmitterInterface $emitter) { new ConcurrencyPlugin($emitter); };
$ vendor/bin/peridot --concurrent
class DotReporterPlugin { // ... protected function listen() { $this->emitter->on('peridot.reporters', [$this, 'onPeridotReporters']); } public function onPeridotReporters(InputInterface $input, ReporterFactory $reporters) { $reporters->register('dot', 'dot matrix', 'Peridot\Reporter\Dot\DotReporter'); } }
namespace Peridot\Reporter\Dot; use Peridot\Reporter\AbstractBaseReporter; class DotReporter extends AbstractBaseReporter { public function init() { $this->eventEmitter->on('test.passed', [$this, 'onTestPassed']); $this->eventEmitter->on('test.failed', [$this, 'onTestFailed']); $this->eventEmitter->on('test.pending', [$this, 'onTestPending']); $this->eventEmitter->on('runner.end', [$this, 'onRunnerEnd']); } }
use Peridot\Reporter\Dot\DotReporterPlugin; return function(EventEmitterInterface $emitter) { new DotReporterPlugin($emitter); };
$ vendor/bin/peridot -r dot
use Evenement\EventEmitterInterface; use Peridot\Reporter\CodeCoverageReporters; return function (EventEmitterInterface $eventEmitter) { (new CodeCoverageReporters($eventEmitter))->register(); $eventEmitter->on('code-coverage.start', function ($reporter) { $reporter->addDirectoryToWhitelist(__DIR__ . '/src'); }); };
$ vendor/bin/peridot -r html-code-coverage --code-coverage-path coverage/
class MyScopePlugin { // ... protected function listen() { $this->emitter->on('suite.start', [$this, 'onSuiteStart']); } public function onSuiteStart(Suite $suite) { $suite->getScope()->peridotAddChildScope(new MyScope()); } }
class MyScope { // tests can access $this->thingy public $thingy; // tests can call $this->doThingyMagic() public function doThingyMagic() { // magic happens! } }
use Evenement\EventEmitterInterface; return function (EventEmitterInterface $eventEmitter) { new MyScopePlugin($eventEmitter); };
describe('A thing', function () { $scope = new MyScope(); $this->peridotAddChildScope($scope); it('should do a thing', function() { $this->doThingyMagic() }); }
describe('A thing', function() { beforeEach(function () { // get a \Prophecy\Prophet $prophet = $this->getProphet() )}; });
describe('My\Thing', function() { it('should be a Thing', function() { assert($this->subject->reveal() instanceof Thing); }); });
describe('My API', function() { describe('/my-route', function() { it('should return data', function() { $this->client->request('GET', '/my-route'); $data = json_decode($this->client->getResponse()->getContent(), true); // assert($data blah blah blah... }); }); });
use Evenement\EventEmitterInterface; use Peridot\Plugin\Doctrine\DoctrinePlugin; use Peridot\Plugin\Doctrine\EntityManager\EntityManagerService; return function (EventEmitterInterface $eventEmitter) { new DoctrinePlugin($eventEmitter, new EntityManagerService()); };
beforeEach(function () { // I can create an entity manager! $this->entityManager = $this->createEntityManager(); $this->repository = new MyRepository($this->entityManager); });
Customize your entity manager creation
use Doctrine\DBAL\Types\Type; Type::addType('datetimeutc', 'ASM\Doctrine\DBAL\Types\DateTimeUTCType'); $factory = function () { // do something that creates an entity manager .. return $entityManager; }; $service = (new EntityManagerService())->setEntityManagerFactory($factory); new DoctrinePlugin($eventEmitter, $service);
Copying is faster than creating
use Nelmio\Alice\Fixtures; use Peridot\Plugin\Doctrine\EntityManager\SchemaService; // create the initial sqlite db used for testing $eventEmitter->on('runner.start', function () use ($factory) { $entityManager = $factory(); $schemaService = new SchemaService($entityManager); $schemaService->dropDatabase()->createDatabase(); Fixtures::load([__DIR__ . '/path/to/fixture.yml'], $entityManager); // load more fixtures... copy(__DIR__ . '/tmp/db.db', __DIR__ . '/tmp/clean.db'); }); // create a clean copy of the db before an entity manager is created $eventEmitter->on('doctrine.entityManager.preCreate', function () { copy(__DIR__ . '/tmp/clean.db', __DIR__ . '/tmp/db.db'); });
An assertion library to complement Peridot.
$ composer require peridot-php/leo:~1.0
use Peridot\Leo\Interfaces\Assert; $assert = new Assert(); $assert->typeOf('string', 'hello', 'is string'); $assert->operator(5, '<', 6, 'should be less than'); $assert->isResource(tempfile()); $assert->throws(function() { throw new Exception("exception"); }, 'Exception');
expect([1,2,3])->to->have->length(3); expect($name)->to->be->a('string') expect($object)->to->have->property('name', 'brian'); expect(function() {})->to->satisfy('is_callable'); expect(5)->to->be->above(4) expect($num)->to->be->within(5, 10); expect('hello')->to->match('/^he/');
use Evenement\EventEmitterInterface; use Peridot\Leo\HttpFoundation\LeoHttpFoundation; use Peridot\Leo\Leo; return function (EventEmitterInterface $eventEmitter) { Leo::assertion()->extend(new LeoHttpFoundation()); };
expect($response)->to->allow(['POST', 'GET']); expect($response)->to->have->status(200); expect($response)->json->to->have->property('name');