Skip to content

Commit

Permalink
[TesterBundle] PHPUnit DoctrineTransactionExtension base on dama/doct…
Browse files Browse the repository at this point in the history
…rine-test-bundle
  • Loading branch information
mpoiriert committed Aug 24, 2024
1 parent 3ca4cac commit 959bb64
Show file tree
Hide file tree
Showing 13 changed files with 226 additions and 27 deletions.
3 changes: 2 additions & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
70 changes: 69 additions & 1 deletion composer.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions config/bundles.php
Original file line number Diff line number Diff line change
Expand Up @@ -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],
];
5 changes: 5 additions & 0 deletions config/packages/dama_doctrine_test_bundle.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
when@test:
dama_doctrine_test:
enable_static_connection: true
enable_static_meta_data_cache: true
enable_static_query_cache: true
1 change: 1 addition & 0 deletions config/packages/doctrine.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
2 changes: 2 additions & 0 deletions packages/messenger/Tests/Transport/DrawTransportTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -28,6 +29,7 @@
use Symfony\Component\Messenger\Transport\TransportInterface;

#[CoversClass(DrawTransport::class)]
#[NoTransaction]
class DrawTransportTest extends TestCase
{
use MockTrait;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
<?php

namespace Draw\Bundle\TesterBundle\PHPUnit\Extension\DoctrineTransaction;

use DAMA\DoctrineTestBundle\Doctrine\DBAL\StaticDriver;
use PHPUnit\Event\TestSuite\Finished as TestSuiteFinished;
use PHPUnit\Event\TestSuite\FinishedSubscriber as TestSuiteFinishedSubscriber;
use PHPUnit\Event\TestSuite\Started as TestSuiteStarted;
use PHPUnit\Event\TestSuite\StartedSubscriber as TestSuiteStartedSubscriber;
use PHPUnit\Runner\Extension\Extension;
use PHPUnit\Runner\Extension\Facade;
use PHPUnit\Runner\Extension\ParameterCollection;
use PHPUnit\TextUI\Configuration\Configuration;

final class DoctrineTransactionExtension implements Extension
{
public static bool $transactionStarted = false;

public static function rollBack(): void
{
if (!self::$transactionStarted) {
return;
}

StaticDriver::rollBack();
self::$transactionStarted = false;
}

public static function begin(): void
{
if (self::$transactionStarted) {
return;
}

StaticDriver::beginTransaction();
self::$transactionStarted = true;
}

#[\Override]
public function bootstrap(Configuration $configuration, Facade $facade, ParameterCollection $parameters): void
{
$facade->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();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<?php

namespace Draw\Bundle\TesterBundle\PHPUnit\Extension\DoctrineTransaction;

#[\Attribute(\Attribute::TARGET_CLASS)]
class NoTransaction
{
}
35 changes: 35 additions & 0 deletions packages/tester-bundle/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -169,3 +169,38 @@ class MyTest extends WebTestCase implements AutowiredInterface
This is the same client as the one you get from the `WebTestCase`, you can use it the same way.

Note that the `AutowireClient` attribute have an `options` and `server` parameters like you would do when calling the `createClient` method.

### DoctrineTransaction

Base on `dama/doctrine-test-bundle` this extension will start a transaction before each test class and rollback it after the test.

By using test class instead of test method, like the original bundle does, it will ease dependencies managements.

Make sure to configure this extension first in your phpunit configuration file.

```xml
<phpunit bootstrap="vendor/autoload.php">
<extensions>
<bootstrap class="Draw\Component\Tester\PHPUnit\Extension\DoctrineTransaction\DoctrineTransactionExtension"/>
</extensions>
</phpunit>
```

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
{
/*...*/
}
}
```
1 change: 1 addition & 0 deletions phpunit.xml.dist
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
</exclude>
</source>
<extensions>
<bootstrap class="Draw\Bundle\TesterBundle\PHPUnit\Extension\DoctrineTransaction\DoctrineTransactionExtension" />
<bootstrap class="Draw\Bundle\TesterBundle\PHPUnit\Extension\DeleteTemporaryEntity\DeleteTemporaryEntityExtension">
<parameter name="ignoreMissingService" value="1" />
</bootstrap>
Expand Down
12 changes: 12 additions & 0 deletions symfony.lock
Original file line number Diff line number Diff line change
Expand Up @@ -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"
},
Expand Down
33 changes: 8 additions & 25 deletions tests/Controller/Security/TwoFactorAuthorizationTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand All @@ -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('[email protected]');
$user->setPlainPassword('test');
Expand All @@ -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());
Expand All @@ -76,6 +58,7 @@ public function testLoginRedirectEnable2fa(): void
);
}

#[Depends('testCreateUser')]
public function testCancel(): void
{
$this->client->followRedirects();
Expand All @@ -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()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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('[email protected]');
Expand Down

0 comments on commit 959bb64

Please sign in to comment.