Skip to content

Commit a786b04

Browse files
committed
feat: force PHPUnit extension usage
1 parent a0857c5 commit a786b04

12 files changed

+221
-67
lines changed

phpunit-deprecation-baseline.xml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44
<line number="25" hash="c6af5d66288d0667e424978000f29571e4954b81">
55
<issue><![CDATA[Since symfony/framework-bundle 6.4: Not setting the "framework.php_errors.log" config option is deprecated. It will default to "true" in 7.0.]]></issue>
66
<issue><![CDATA[Since symfony/var-exporter 7.3: Generating lazy proxy for class "Zenstruck\Foundry\Tests\Integration\ForceFactoriesTraitUsage\SomeObject" is deprecated; leverage native lazy objects instead.]]></issue>
7+
<issue><![CDATA[Since zenstruck/foundry 2.7: Trait Zenstruck\Foundry\Test\Factories is deprecated and will be removed in Foundry 3.]]></issue>
8+
<issue><![CDATA[Since zenstruck/foundry 2.7: Not using Foundry's PHPUnit extension is deprecated and will throw an error in Foundry 3.]]></issue>
79
</line>
810
</file>
911
</files>

src/Configuration.php

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@
1919
use Zenstruck\Foundry\InMemory\CannotEnableInMemory;
2020
use Zenstruck\Foundry\InMemory\InMemoryRepositoryRegistry;
2121
use Zenstruck\Foundry\Persistence\PersistenceManager;
22+
use Zenstruck\Foundry\PHPUnit\FoundryExtension;
23+
use Zenstruck\Foundry\Test\Factories;
2224

2325
/**
2426
* @author Kevin Bond <kevinbond@gmail.com>
@@ -128,6 +130,10 @@ public static function isBooted(): bool
128130
public static function boot(\Closure|self $configuration): void
129131
{
130132
self::$instance = $configuration;
133+
134+
if (FoundryExtension::shouldBeEnabled()) {
135+
trigger_deprecation('zenstruck/foundry', '2.7', 'Not using Foundry\'s PHPUnit extension is deprecated and will throw an error in Foundry 3.');
136+
}
131137
}
132138

133139
/** @param \Closure():self|self $configuration */

src/Exception/FoundryNotBooted.php

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,19 @@
1111

1212
namespace Zenstruck\Foundry\Exception;
1313

14+
use Zenstruck\Foundry\PHPUnit\FoundryExtension;
15+
1416
/**
1517
* @author Kevin Bond <kevinbond@gmail.com>
1618
*/
1719
final class FoundryNotBooted extends \LogicException
1820
{
1921
public function __construct()
2022
{
21-
parent::__construct('Foundry is not yet booted. Ensure ZenstruckFoundryBundle is enabled. If in a test, ensure your TestCase has the Factories trait.');
23+
$message = FoundryExtension::isEnabled()
24+
? 'Foundry is not yet booted. Ensure ZenstruckFoundryBundle is enabled. If in a test, ensure Foundry\'s PHPUnit extension is enabled.'
25+
: 'Foundry is not yet booted. Ensure ZenstruckFoundryBundle is enabled. If in a test, ensure your TestCase has the Factories trait.';
26+
27+
parent::__construct($message);
2228
}
2329
}

src/PHPUnit/BootFoundryOnDataProviderMethodCalled.php

Lines changed: 30 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,11 @@
1414
namespace Zenstruck\Foundry\PHPUnit;
1515

1616
use PHPUnit\Event;
17+
use PHPUnit\Framework\TestCase;
18+
use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase;
1719
use Zenstruck\Foundry\Configuration;
1820
use Zenstruck\Foundry\InMemory\AsInMemoryTest;
21+
use Zenstruck\Foundry\Test\UnitTestConfig;
1922

2023
/**
2124
* @internal
@@ -25,14 +28,38 @@ final class BootFoundryOnDataProviderMethodCalled implements Event\Test\DataProv
2528
{
2629
public function notify(Event\Test\DataProviderMethodCalled $event): void
2730
{
28-
if (\method_exists($event->testMethod()->className(), '_bootForDataProvider')) {
29-
$event->testMethod()->className()::_bootForDataProvider();
30-
}
31+
$this->bootFoundryForDataProvider($event->testMethod()->className());
3132

3233
$testMethod = $event->testMethod();
3334

3435
if (AsInMemoryTest::shouldEnableInMemory($testMethod->className(), $testMethod->methodName())) {
3536
Configuration::instance()->enableInMemory();
3637
}
3738
}
39+
40+
/**
41+
* @param class-string $className
42+
*/
43+
private function bootFoundryForDataProvider(string $className): void
44+
{
45+
if (!\is_subclass_of($className, TestCase::class)) {
46+
return;
47+
}
48+
49+
// unit test
50+
if (!\is_subclass_of($className, KernelTestCase::class)) {
51+
Configuration::bootForDataProvider(UnitTestConfig::build());
52+
53+
return;
54+
}
55+
56+
// integration test
57+
Configuration::bootForDataProvider(static function(): Configuration {
58+
if (!KernelTestCaseHelper::getContainer()->has('.zenstruck_foundry.configuration')) {
59+
throw new \LogicException('ZenstruckFoundryBundle is not enabled. Ensure it is added to your config/bundles.php.');
60+
}
61+
62+
return KernelTestCaseHelper::getContainer()->get('.zenstruck_foundry.configuration'); // @phpstan-ignore return.type
63+
});
64+
}
3865
}
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
/*
6+
* This file is part of the zenstruck/foundry package.
7+
*
8+
* (c) Kevin Bond <kevinbond@gmail.com>
9+
*
10+
* For the full copyright and license information, please view the LICENSE
11+
* file that was distributed with this source code.
12+
*/
13+
14+
namespace Zenstruck\Foundry\PHPUnit;
15+
16+
use PHPUnit\Event;
17+
use PHPUnit\Framework\TestCase;
18+
use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase;
19+
use Zenstruck\Foundry\Configuration;
20+
use Zenstruck\Foundry\Test\UnitTestConfig;
21+
22+
/**
23+
* @internal
24+
* @author Nicolas PHILIPPE <nikophil@gmail.com>
25+
*/
26+
final class BootFoundryOnPreparationStarted implements Event\Test\PreparationStartedSubscriber
27+
{
28+
public function notify(Event\Test\PreparationStarted $event): void
29+
{
30+
if (!$event->test()->isTestMethod()) {
31+
return;
32+
}
33+
34+
$this->bootFoundry($event->test()->className());
35+
}
36+
37+
/**
38+
* @param class-string $className
39+
*/
40+
private function bootFoundry(string $className): void
41+
{
42+
if (!\is_subclass_of($className, TestCase::class)) {
43+
return;
44+
}
45+
46+
// unit test
47+
if (!\is_subclass_of($className, KernelTestCase::class)) {
48+
Configuration::boot(UnitTestConfig::build());
49+
50+
return;
51+
}
52+
53+
// integration test
54+
Configuration::boot(static function(): Configuration {
55+
if (!KernelTestCaseHelper::getContainer()->has('.zenstruck_foundry.configuration')) {
56+
throw new \LogicException('ZenstruckFoundryBundle is not enabled. Ensure it is added to your config/bundles.php.');
57+
}
58+
59+
return KernelTestCaseHelper::getContainer()->get('.zenstruck_foundry.configuration'); // @phpstan-ignore return.type
60+
});
61+
}
62+
}

src/PHPUnit/FoundryExtension.php

Lines changed: 52 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -22,30 +22,62 @@
2222
* @internal
2323
* @author Nicolas PHILIPPE <nikophil@gmail.com>
2424
*/
25-
final class FoundryExtension implements Runner\Extension\Extension
26-
{
27-
public function bootstrap(
28-
TextUI\Configuration\Configuration $configuration,
29-
Runner\Extension\Facade $facade,
30-
Runner\Extension\ParameterCollection $parameters,
31-
): void {
32-
// shutdown Foundry if for some reason it has been booted before
33-
if (Configuration::isBooted()) {
34-
Configuration::shutdown();
25+
26+
if (interface_exists(Runner\Extension\Extension::class)) {
27+
final class FoundryExtension implements Runner\Extension\Extension
28+
{
29+
private static bool $enabled = false;
30+
31+
public function bootstrap(
32+
TextUI\Configuration\Configuration $configuration,
33+
Runner\Extension\Facade $facade,
34+
Runner\Extension\ParameterCollection $parameters,
35+
): void {
36+
// shutdown Foundry if for some reason it has been booted before
37+
if (Configuration::isBooted()) {
38+
Configuration::shutdown();
39+
}
40+
41+
$subscribers = [
42+
new BuildStoryOnTestPrepared(),
43+
new EnableInMemoryBeforeTest(),
44+
new DisplayFakerSeedOnTestSuiteFinished(),
45+
new BootFoundryOnPreparationStarted(),
46+
new ShutdownFoundryOnTestFinished(),
47+
];
48+
49+
if (ConstraintRequirement::from('>=11.4')->isSatisfiedBy(Runner\Version::id())) {
50+
// those deal with data provider events which can be useful only if PHPUnit >=11.4 is used
51+
$subscribers[] = new BootFoundryOnDataProviderMethodCalled();
52+
$subscribers[] = new ShutdownFoundryOnDataProviderMethodFinished();
53+
}
54+
55+
$facade->registerSubscribers(...$subscribers);
56+
57+
self::$enabled = true;
3558
}
3659

37-
$subscribers = [
38-
new BuildStoryOnTestPrepared(),
39-
new EnableInMemoryBeforeTest(),
40-
new DisplayFakerSeedOnTestSuiteFinished(),
41-
];
60+
public static function shouldBeEnabled(): bool
61+
{
62+
return !self::isEnabled() && ConstraintRequirement::from('>=10')->isSatisfiedBy(Runner\Version::id());
63+
}
4264

43-
if (ConstraintRequirement::from('>=11.4')->isSatisfiedBy(Runner\Version::id())) {
44-
// those deal with data provider events which can be useful only if PHPUnit >=11.4 is used
45-
$subscribers[] = new BootFoundryOnDataProviderMethodCalled();
46-
$subscribers[] = new ShutdownFoundryOnDataProviderMethodFinished();
65+
public static function isEnabled(): bool
66+
{
67+
return self::$enabled;
68+
}
69+
}
70+
} else {
71+
final class FoundryExtension
72+
{
73+
public static function shouldBeEnabled(): bool
74+
{
75+
return false;
4776
}
4877

49-
$facade->registerSubscribers(...$subscribers);
78+
public static function isEnabled(): bool
79+
{
80+
return false;
81+
}
5082
}
5183
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
<?php
2+
3+
namespace Zenstruck\Foundry\PHPUnit;
4+
5+
use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase;
6+
use Symfony\Component\DependencyInjection\Container;
7+
8+
final class KernelTestCaseHelper extends KernelTestCase
9+
{
10+
public static function getContainer(): Container
11+
{
12+
return parent::getContainer();
13+
}
14+
}

src/PHPUnit/ShutdownFoundryOnDataProviderMethodFinished.php

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
namespace Zenstruck\Foundry\PHPUnit;
1515

1616
use PHPUnit\Event;
17+
use Zenstruck\Foundry\Configuration;
1718

1819
/**
1920
* @internal
@@ -23,8 +24,8 @@ final class ShutdownFoundryOnDataProviderMethodFinished implements Event\Test\Da
2324
{
2425
public function notify(Event\Test\DataProviderMethodFinished $event): void
2526
{
26-
if (\method_exists($event->testMethod()->className(), '_shutdownAfterDataProvider')) {
27-
$event->testMethod()->className()::_shutdownAfterDataProvider();
28-
}
27+
KernelTestCaseHelper::tearDownAfterClass();
28+
29+
Configuration::shutdown();
2930
}
3031
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
/*
6+
* This file is part of the zenstruck/foundry package.
7+
*
8+
* (c) Kevin Bond <kevinbond@gmail.com>
9+
*
10+
* For the full copyright and license information, please view the LICENSE
11+
* file that was distributed with this source code.
12+
*/
13+
14+
namespace Zenstruck\Foundry\PHPUnit;
15+
16+
use PHPUnit\Event;
17+
use Zenstruck\Foundry\Configuration;
18+
19+
/**
20+
* @internal
21+
* @author Nicolas PHILIPPE <nikophil@gmail.com>
22+
*/
23+
final class ShutdownFoundryOnTestFinished implements Event\Test\FinishedSubscriber
24+
{
25+
public function notify(Event\Test\Finished $event): void
26+
{
27+
Configuration::shutdown();
28+
}
29+
}

src/Test/Factories.php

Lines changed: 13 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@
1616
use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase;
1717
use Zenstruck\Foundry\Configuration;
1818

19+
use Zenstruck\Foundry\PHPUnit\FoundryExtension;
20+
1921
use function Zenstruck\Foundry\Persistence\initialize_proxy_object;
2022

2123
/**
@@ -27,58 +29,31 @@ trait Factories
2729
* @internal
2830
* @before
2931
*/
30-
#[Before]
32+
#[Before(10)]
3133
public function _beforeHook(): void
3234
{
33-
$this->_bootFoundry();
34-
$this->_loadDataProvidedProxies();
35-
}
35+
$this->_loadDataProvidedProxies(); // todo remove
3636

37-
/**
38-
* @internal
39-
* @after
40-
*/
41-
#[After]
42-
public static function _shutdownFoundry(): void
43-
{
44-
Configuration::shutdown();
45-
}
46-
47-
/**
48-
* @see \Zenstruck\Foundry\PHPUnit\BootFoundryOnDataProviderMethodCalled
49-
* @internal
50-
*/
51-
public static function _bootForDataProvider(): void
52-
{
53-
if (!\is_subclass_of(static::class, KernelTestCase::class)) { // @phpstan-ignore function.impossibleType, function.alreadyNarrowedType
54-
// unit test
55-
Configuration::bootForDataProvider(UnitTestConfig::build());
37+
if (FoundryExtension::isEnabled()) {
38+
trigger_deprecation('zenstruck/foundry', '2.7', sprintf('Trait %s is deprecated and will be removed in Foundry 3.', Factories::class));
5639

5740
return;
5841
}
5942

60-
// integration test
61-
Configuration::bootForDataProvider(static function(): Configuration {
62-
if (!static::getContainer()->has('.zenstruck_foundry.configuration')) { // @phpstan-ignore staticMethod.notFound
63-
throw new \LogicException('ZenstruckFoundryBundle is not enabled. Ensure it is added to your config/bundles.php.');
64-
}
65-
66-
return static::getContainer()->get('.zenstruck_foundry.configuration'); // @phpstan-ignore staticMethod.notFound, return.type
67-
});
43+
$this->_bootFoundry();
6844
}
6945

7046
/**
7147
* @internal
72-
* @see \Zenstruck\Foundry\PHPUnit\ShutdownFoundryOnDataProviderMethodFinished
48+
* @after
7349
*/
74-
public static function _shutdownAfterDataProvider(): void
50+
#[After(10)]
51+
public static function _shutdownFoundry(): void
7552
{
76-
if (\is_subclass_of(static::class, KernelTestCase::class)) { // @phpstan-ignore function.impossibleType, function.alreadyNarrowedType
77-
self::ensureKernelShutdown(); // @phpstan-ignore staticMethod.notFound
78-
static::$class = null; // @phpstan-ignore staticProperty.notFound
79-
static::$kernel = null; // @phpstan-ignore staticProperty.notFound
80-
static::$booted = false; // @phpstan-ignore staticProperty.notFound
53+
if (FoundryExtension::isEnabled()) {
54+
return;
8155
}
56+
8257
Configuration::shutdown();
8358
}
8459

0 commit comments

Comments
 (0)