Skip to content

Instantly share code, notes, and snippets.

@jakzal
Last active September 23, 2020 12:23
Show Gist options
  • Star 4 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save jakzal/80b5e08a49cec484d2f5cb396581d2a8 to your computer and use it in GitHub Desktop.
Save jakzal/80b5e08a49cec484d2f5cb396581d2a8 to your computer and use it in GitHub Desktop.
Set global variables with PHPUnit test method annotations
<?php
declare(strict_types=1);
namespace Zalas\Tests;
use PHPUnit\Framework\TestCase;
class ExampleTest extends TestCase
{
/**
* @env APP_ENV=foo
* @env APP_DEBUG=0
* @server APP_ENV=bar
* @server APP_DEBUG=1
*/
public function test_global_variables()
{
$this->assertSame('foo', $_ENV['APP_ENV']);
$this->assertSame('0', $_ENV['APP_DEBUG']);
$this->assertSame('bar', $_SERVER['APP_ENV']);
$this->assertSame('1', $_SERVER['APP_DEBUG']);
}
}
<?php
declare(strict_types=1);
namespace Zalas\Tests;
use PHPUnit\Framework\Test;
use PHPUnit\Framework\TestCase;
use PHPUnit\Framework\TestListener;
use PHPUnit\Framework\TestListenerDefaultImplementation;
/**
* Enables @env and @server annotations on test classes and methods.
*
* Examples:
*
* <code>
* @env APP_ENV=bar
* @server APP_DEBUG=1
* @server FOO=
* </code>
*/
final class GlobalAnnotationsListener implements TestListener
{
use TestListenerDefaultImplementation;
private $server;
private $env;
public function startTest(Test $test): void
{
if ($test instanceof TestCase) {
$this->backupGlobals();
$this->readGlobalAnnotations($test);
}
}
public function endTest(Test $test, float $time): void
{
$this->restoreGlobals();
}
private function backupGlobals(): void
{
$this->server = $_SERVER;
$this->env = $_ENV;
}
private function restoreGlobals(): void
{
if (null !== $this->server) {
$_SERVER = $this->server;
}
if (null !== $this->env) {
$_ENV = $this->env;
}
}
private function readGlobalAnnotations(TestCase $test): void
{
$globalVars = $this->parseGlobalAnnotations($test);
if (!empty($globalVars['env'])) {
foreach ($globalVars['env'] as $name => $value) {
$_ENV[$name] = $value;
}
}
if (!empty($globalVars['server'])) {
foreach ($globalVars['server'] as $name => $value) {
$_SERVER[$name] = $value;
}
}
}
private function parseGlobalAnnotations(TestCase $test): array
{
$annotations = $test->getAnnotations();
$globalVarAnnotations = array_filter(
array_merge_recursive($annotations['class'], $annotations['method']),
function ($annotationName) {
return in_array($annotationName, ['env', 'server']);
},
ARRAY_FILTER_USE_KEY
);
return array_map(function ($annotations) {
return array_reduce($annotations, function ($carry, $annotation) {
if (!strpos($annotation, '=')) {
$carry[$annotation] = '';
} else {
list($name, $value) = explode('=', $annotation, 2);
$carry[$name] = $value;
}
return $carry;
}, []);
}, $globalVarAnnotations);
}
}
<?xml version="1.0" encoding="UTF-8"?>
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/6.5/phpunit.xsd"
bootstrap="vendor/autoload.php"
forceCoversAnnotation="false"
beStrictAboutCoversAnnotation="true"
beStrictAboutOutputDuringTests="true"
beStrictAboutTodoAnnotatedTests="true"
verbose="true"
colors="true">
<testsuite name="default">
<directory suffix="Test.php">tests</directory>
</testsuite>
<listeners>
<listener class="Zalas\Tests\GlobalAnnotationsListener" />
</listeners>
<filter>
<whitelist processUncoveredFilesFromWhitelist="true">
<directory suffix=".php">src</directory>
</whitelist>
</filter>
</phpunit>
@jakzal
Copy link
Author

jakzal commented Mar 1, 2018

The above approach was used to create the library zalas/phpunit-globals library: https://github.com/jakzal/phpunit-globals

composer require --dev zalas/phpunit-globals

@bolechen
Copy link

The above approach was used to create the library zalas/phpunit-globals library: https://github.com/jakzal/phpunit-globals

composer require --dev zalas/phpunit-globals

Not work with brianium/paratest last version, any idea?

@jakzal
Copy link
Author

jakzal commented Sep 23, 2020

@bolechen define "not working" ;)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment