diff --git a/composer.json b/composer.json
index 68a1b140..794385b4 100644
--- a/composer.json
+++ b/composer.json
@@ -124,7 +124,8 @@
"symfony/twig-bundle": "^6.4.0",
"symfony/var-dumper": "^6.4.0",
"symfony/var-exporter": "^6.4.0",
- "symfony/web-profiler-bundle": "^6.4.0"
+ "symfony/web-profiler-bundle": "^6.4.0",
+ "dama/doctrine-test-bundle": "^8.2"
},
"replace": {
"draw/application": "self.version",
diff --git a/composer.lock b/composer.lock
index d21c4037..000efd3a 100644
--- a/composer.lock
+++ b/composer.lock
@@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
- "content-hash": "afa45b5f9c1922d8b63499adcd901de8",
+ "content-hash": "1c85073d453ff2c2f4ff118ab6f28d1d",
"packages": [
{
"name": "aws/aws-crt-php",
@@ -13075,6 +13075,73 @@
},
"time": "2022-12-20T22:53:13+00:00"
},
+ {
+ "name": "dama/doctrine-test-bundle",
+ "version": "v8.2.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/dmaicher/doctrine-test-bundle.git",
+ "reference": "1f81a280ea63f049d24e9c8ce00e557b18e0ff2f"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/dmaicher/doctrine-test-bundle/zipball/1f81a280ea63f049d24e9c8ce00e557b18e0ff2f",
+ "reference": "1f81a280ea63f049d24e9c8ce00e557b18e0ff2f",
+ "shasum": ""
+ },
+ "require": {
+ "doctrine/dbal": "^3.3 || ^4.0",
+ "doctrine/doctrine-bundle": "^2.11.0",
+ "php": "^7.4 || ^8.0",
+ "psr/cache": "^1.0 || ^2.0 || ^3.0",
+ "symfony/cache": "^5.4 || ^6.3 || ^7.0",
+ "symfony/framework-bundle": "^5.4 || ^6.3 || ^7.0"
+ },
+ "require-dev": {
+ "behat/behat": "^3.0",
+ "friendsofphp/php-cs-fixer": "^3.27",
+ "phpstan/phpstan": "^1.2",
+ "phpunit/phpunit": "^8.0 || ^9.0 || ^10.0 || ^11.0",
+ "symfony/phpunit-bridge": "^6.3",
+ "symfony/process": "^5.4 || ^6.3 || ^7.0",
+ "symfony/yaml": "^5.4 || ^6.3 || ^7.0"
+ },
+ "type": "symfony-bundle",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "8.x-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "DAMA\\DoctrineTestBundle\\": "src/DAMA/DoctrineTestBundle"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "David Maicher",
+ "email": "mail@dmaicher.de"
+ }
+ ],
+ "description": "Symfony bundle to isolate doctrine database tests and improve test performance",
+ "keywords": [
+ "doctrine",
+ "isolation",
+ "performance",
+ "symfony",
+ "testing",
+ "tests"
+ ],
+ "support": {
+ "issues": "https://github.com/dmaicher/doctrine-test-bundle/issues",
+ "source": "https://github.com/dmaicher/doctrine-test-bundle/tree/v8.2.0"
+ },
+ "time": "2024-05-28T15:41:06+00:00"
+ },
{
"name": "dasprid/enum",
"version": "1.0.5",
@@ -15420,6 +15487,7 @@
"prefer-lowest": false,
"platform": {
"ext-ctype": "*",
+ "ext-dom": "*",
"ext-iconv": "*",
"ext-json": "*",
"ext-mongodb": "*",
diff --git a/config/bundles.php b/config/bundles.php
index a4b46ba5..fb037109 100644
--- a/config/bundles.php
+++ b/config/bundles.php
@@ -30,4 +30,5 @@
Draw\Bundle\SonataImportBundle\DrawSonataImportBundle::class => ['all' => true],
Knp\DoctrineBehaviors\DoctrineBehaviorsBundle::class => ['all' => true],
Symfony\Bundle\MakerBundle\MakerBundle::class => ['dev' => true],
+ DAMA\DoctrineTestBundle\DAMADoctrineTestBundle::class => ['test' => true],
];
diff --git a/config/packages/dama_doctrine_test_bundle.yaml b/config/packages/dama_doctrine_test_bundle.yaml
new file mode 100644
index 00000000..3482cbae
--- /dev/null
+++ b/config/packages/dama_doctrine_test_bundle.yaml
@@ -0,0 +1,5 @@
+when@test:
+ dama_doctrine_test:
+ enable_static_connection: true
+ enable_static_meta_data_cache: true
+ enable_static_query_cache: true
diff --git a/config/packages/doctrine.yaml b/config/packages/doctrine.yaml
index 95707cef..6f9b7845 100644
--- a/config/packages/doctrine.yaml
+++ b/config/packages/doctrine.yaml
@@ -14,6 +14,7 @@ doctrine:
schema_filter: '~^(?!messenger_messages|draw_messenger__message|draw_messenger__message_tag)~'
driver: 'pdo_mysql'
server_version: '8.0.23'
+ use_savepoints: true
logging: true
charset: 'utf8mb4'
default_table_options:
diff --git a/packages/messenger/Tests/Transport/DrawTransportTest.php b/packages/messenger/Tests/Transport/DrawTransportTest.php
index 197045dd..4261d17b 100644
--- a/packages/messenger/Tests/Transport/DrawTransportTest.php
+++ b/packages/messenger/Tests/Transport/DrawTransportTest.php
@@ -3,6 +3,7 @@
namespace Draw\Component\Messenger\Tests\Transport;
use Doctrine\DBAL\Connection;
+use Draw\Bundle\TesterBundle\PHPUnit\Extension\DoctrineTransaction\NoTransaction;
use Draw\Component\Messenger\Expirable\PurgeableTransportInterface;
use Draw\Component\Messenger\Expirable\Stamp\ExpirationStamp;
use Draw\Component\Messenger\Searchable\SearchableTransportInterface;
@@ -28,6 +29,7 @@
use Symfony\Component\Messenger\Transport\TransportInterface;
#[CoversClass(DrawTransport::class)]
+#[NoTransaction]
class DrawTransportTest extends TestCase
{
use MockTrait;
diff --git a/packages/tester-bundle/PHPUnit/Extension/DoctrineTransaction/DoctrineTransactionExtension.php b/packages/tester-bundle/PHPUnit/Extension/DoctrineTransaction/DoctrineTransactionExtension.php
new file mode 100644
index 00000000..da5d47d7
--- /dev/null
+++ b/packages/tester-bundle/PHPUnit/Extension/DoctrineTransaction/DoctrineTransactionExtension.php
@@ -0,0 +1,80 @@
+registerSubscribers(
+ new class() implements TestSuiteStartedSubscriber {
+ public function notify(TestSuiteStarted $event): void
+ {
+ $class = $event->testSuite()->name();
+
+ DoctrineTransactionExtension::startTransactionIfNeeded($class);
+ }
+ },
+ new class() implements TestSuiteFinishedSubscriber {
+ public function notify(TestSuiteFinished $event): void
+ {
+ DoctrineTransactionExtension::rollBack();
+ StaticDriver::setKeepStaticConnections(false);
+ }
+ },
+ );
+ }
+
+ private static function asNoTransaction(string $class): bool
+ {
+ if (!class_exists($class)) {
+ return false;
+ }
+
+ return (bool) \count((new \ReflectionClass($class))->getAttributes(NoTransaction::class));
+ }
+
+ public static function startTransactionIfNeeded(string $class): void
+ {
+ if (self::asNoTransaction($class)) {
+ return;
+ }
+
+ StaticDriver::setKeepStaticConnections(true);
+
+ static::begin();
+ }
+}
diff --git a/packages/tester-bundle/PHPUnit/Extension/DoctrineTransaction/NoTransaction.php b/packages/tester-bundle/PHPUnit/Extension/DoctrineTransaction/NoTransaction.php
new file mode 100644
index 00000000..196c733c
--- /dev/null
+++ b/packages/tester-bundle/PHPUnit/Extension/DoctrineTransaction/NoTransaction.php
@@ -0,0 +1,8 @@
+
+
+
+
+
+```
+
+Also if one of your test should not have transaction you can use the `NoTransaction` attribute on the test class.
+
+```php
+
+namespace App\Tests;
+
+use Draw\Bundle\TesterBundle\PHPUnit\Extension\DoctrineTransaction\NoTransaction;
+use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase;
+
+#[NoTransaction]
+class MyTest extends KernelTestCase
+{
+ public function testSomething(): void
+ {
+ /*...*/
+ }
+}
+```
\ No newline at end of file
diff --git a/phpunit.xml.dist b/phpunit.xml.dist
index eae99d8e..4d2edb7b 100644
--- a/phpunit.xml.dist
+++ b/phpunit.xml.dist
@@ -39,6 +39,7 @@
+
diff --git a/symfony.lock b/symfony.lock
index 576a29d2..ad422ef1 100644
--- a/symfony.lock
+++ b/symfony.lock
@@ -29,6 +29,18 @@
"composer/semver": {
"version": "3.2.5"
},
+ "dama/doctrine-test-bundle": {
+ "version": "8.2",
+ "recipe": {
+ "repo": "github.com/symfony/recipes-contrib",
+ "branch": "main",
+ "version": "7.2",
+ "ref": "896306d79d4ee143af9eadf9b09fd34a8c391b70"
+ },
+ "files": [
+ "config/packages/dama_doctrine_test_bundle.yaml"
+ ]
+ },
"dasprid/enum": {
"version": "1.0.3"
},
diff --git a/tests/Controller/Security/TwoFactorAuthorizationTest.php b/tests/Controller/Security/TwoFactorAuthorizationTest.php
index e8269bc6..0a94e3c0 100644
--- a/tests/Controller/Security/TwoFactorAuthorizationTest.php
+++ b/tests/Controller/Security/TwoFactorAuthorizationTest.php
@@ -8,9 +8,8 @@
use Draw\Bundle\TesterBundle\PHPUnit\Extension\SetUpAutowire\AutowireService;
use Draw\Bundle\TesterBundle\WebTestCase;
use Draw\Component\Tester\PHPUnit\Extension\SetUpAutowire\AutowiredInterface;
-use PHPUnit\Framework\Attributes\AfterClass;
-use PHPUnit\Framework\Attributes\BeforeClass;
use PHPUnit\Framework\Attributes\Depends;
+use PHPUnit\Framework\Attributes\DoesNotPerformAssertions;
use Symfony\Bundle\FrameworkBundle\KernelBrowser;
use Symfony\Component\DomCrawler\Crawler;
@@ -26,11 +25,9 @@ class TwoFactorAuthorizationTest extends WebTestCase implements AutowiredInterfa
private static User $user;
- public static function setUpBeforeClass(): void
+ #[DoesNotPerformAssertions]
+ public function testCreateUser(): void
{
- $entityManager = static::getContainer()
- ->get(EntityManagerInterface::class);
-
$user = new User();
$user->setEmail('test-2fa@example.com');
$user->setPlainPassword('test');
@@ -39,28 +36,13 @@ public static function setUpBeforeClass(): void
// This role for enabling 2fa as per configuration
$user->enableTwoFActorAuthenticationProvider('totp');
- $entityManager->persist($user);
- $entityManager->flush();
+ $this->entityManager->persist($user);
+ $this->entityManager->flush();
self::$user = $user;
}
- #[
- AfterClass,
- BeforeClass,
- ]
- public static function cleanUp(): void
- {
- static::getContainer()
- ->get(EntityManagerInterface::class)
- ->createQueryBuilder()
- ->delete(User::class, 'user')
- ->andWhere('user.email like :email')
- ->setParameter('email', 'test-2fa%@example.com')
- ->getQuery()
- ->execute();
- }
-
+ #[Depends('testCreateUser')]
public function testLoginRedirectEnable2fa(): void
{
static::assertTrue(self::$user->needToEnableTotpAuthenticationEnabled());
@@ -76,6 +58,7 @@ public function testLoginRedirectEnable2fa(): void
);
}
+ #[Depends('testCreateUser')]
public function testCancel(): void
{
$this->client->followRedirects();
@@ -102,7 +85,7 @@ public function testEnable2faInAdminInvalidCode(): void
self::$user->setRoles(['ROLE_2FA_ADMIN']);
$this->entityManager->flush();
- $crawler = $this->loginToAdmin();
+ $this->loginToAdmin();
$crawler = $this->client->submit(
$this->client->getCrawler()
diff --git a/tests/SonataIntegrationBundle/User/Action/UnlockUserActionTest.php b/tests/SonataIntegrationBundle/User/Action/UnlockUserActionTest.php
index cd82efc4..a69904d3 100644
--- a/tests/SonataIntegrationBundle/User/Action/UnlockUserActionTest.php
+++ b/tests/SonataIntegrationBundle/User/Action/UnlockUserActionTest.php
@@ -5,6 +5,7 @@
use App\Tests\SonataIntegrationBundle\WebTestCaseTrait;
use Draw\Bundle\UserBundle\Entity\UserLock;
use Draw\Component\Tester\PHPUnit\Extension\SetUpAutowire\AutowiredInterface;
+use PHPUnit\Framework\Attributes\Depends;
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
class UnlockUserActionTest extends WebTestCase implements AutowiredInterface
@@ -46,6 +47,7 @@ public function testUnlock(): void
static::assertEqualsWithDelta(new \DateTimeImmutable('+ 24 hours'), $userLock->getUnlockUntil(), 2);
}
+ #[Depends('testUnlock')]
public function testNoAccess(): void
{
$this->login('locked@example.com');