Skip to content

Commit 399cf76

Browse files
authored
Merge pull request #14 from CakeDC/feature/tag-3.1.0
Feature/tag 3.1.0
2 parents bb62fc7 + 77ebdd7 commit 399cf76

17 files changed

Lines changed: 533 additions & 193 deletions

‎.github/workflows/ci.yml‎

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@ name: CI
22

33
on:
44
push:
5+
branches:
6+
- 2.next-cake4
7+
- 3.next-cake5
58

69
pull_request:
710
branches:
@@ -52,8 +55,11 @@ jobs:
5255
- name: Run PHPUnit
5356
run: vendor/bin/phpunit
5457

55-
cs-stan:
56-
name: Coding Standard & Static Analysis
58+
- name: Run integration tests
59+
run: composer test-integration
60+
61+
cs:
62+
name: Coding Standard
5763
runs-on: ubuntu-24.04
5864

5965
steps:

‎CHANGELOG.md‎

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
Changelog
2+
=========
3+
4+
Releases for CakePHP 5.0
5+
------------------------
6+
* 3.1.0
7+
* **Breaking (behaviour)** — the per-test transaction now opens before `setUp()` runs, so data written in `setUp()` (fixtures, factories, `save()`) is rolled back with the test instead of being committed. Tests that relied on `setUp()` data carrying over to later tests in the same class (for example, seeding once behind a static flag) must seed per test.
8+
* **Breaking (API)** — `PHPUnitBeforeTestMethodCalledSubscriber` was removed; register `PHPUnitPreparationStartedSubscriber` instead. Applications that registered the old subscriber by hand will get a fatal error after upgrading.
9+
* Note — do not combine this extension with tests that declare `$fixtures`: CakePHP's `TransactionStrategy` requires no active transaction, and the per-test transaction is already open when `setUp()` runs. Use one strategy or the other.
10+
* Fix: the transaction is opened before `setUp()` (`PreparationStarted`), so `setUp()` data no longer leaks into the next test
11+
* Fix: the per-test transaction is rolled back with `rollback(true)` consistently. Prepared tests are closed on `Test\Finished`; tests that never reach it (unmet requirements, or a skip/error during `setUp()`) are closed by the next test's `PreparationStarted` or by `TestRunner\Finished` at the end of the run. In that case a `tearDownAfterClass()` that runs in between is rolled back with the still-open transaction
12+
* New: SQLite integration suite (`composer test-integration`) proving `setUp()` data does not survive between tests
13+
* New public API: `PHPUnitPreparationStartedSubscriber`, `PHPUnitTestFinishedSubscriber`, `PHPUnitTestRunnerFinishedSubscriber` and `TransactionGuard`, plus the `TestConnectionTrait` helper; `PHPUnitAfterTestMethodFinishedSubscriber` is kept for backwards compatibility
14+
* Chore: `TransactionGuard` centralises begin/end, and the unit tests no longer build PHPUnit internals
15+
* CI: PHP 8.1–8.5 matrix, coding standard job, integration suite, and no duplicate runs on PR branches
16+
17+
Previous releases (3.0.x and earlier) predate this changelog. See the Git history and tags.

‎Docs/Documentation/Overview.md‎

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,12 @@ Generic cycle of test execution under DbTest
1212
--------------------------------------------
1313

1414
* When test suite starts with DbTest, It loads test database from template database snapshot.
15-
* Before test method starts, DbTest initializes the transaction.
16-
* After test method finishes, DbTest rollbacks transaction.
15+
* Before `setUp()` runs, DbTest opens the transaction.
16+
* After the test finishes, DbTest rolls back the transaction.
1717

1818
This way database modifications are quickly restored, but requires that the table uses a transaction engine
19-
like InnoDb.
19+
like InnoDb. Because the transaction is already open when `setUp()` runs, tests using DbTest must not declare
20+
`$fixtures` (CakePHP's fixture transaction strategy cannot run inside an open transaction).
2021

2122
Support
2223
-------

‎composer.json‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,8 @@
4040
"phpstan-baseline": "tools/phpstan --generate-baseline",
4141
"psalm-baseline": "tools/psalm --set-baseline=psalm-baseline.xml",
4242
"stan-setup": "phive install",
43-
"test": "phpunit"
43+
"test": "phpunit",
44+
"test-integration": "phpunit -c phpunit.integration.xml"
4445
},
4546
"config": {
4647
"allow-plugins": {

‎phpunit.integration.xml‎

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<!--
3+
~ Copyright 2013 - 2023, Cake Development Corporation (https://www.cakedc.com)
4+
~
5+
~ Licensed under The MIT License
6+
~ Redistributions of files must retain the above copyright notice.
7+
~
8+
~ @copyright Copyright 2013 - 2023, Cake Development Corporation (https://www.cakedc.com)
9+
~ @license MIT License (http://www.opensource.org/licenses/mit-license.php)
10+
-->
11+
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
12+
colors="true"
13+
processIsolation="false"
14+
stopOnFailure="false"
15+
bootstrap="tests/bootstrap.php"
16+
cacheDirectory=".phpunit.cache"
17+
xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/10.1/phpunit.xsd">
18+
<php>
19+
<ini name="memory_limit" value="-1"/>
20+
<ini name="apc.enable_cli" value="1"/>
21+
</php>
22+
23+
<testsuites>
24+
<testsuite name="DbTest Integration Suite">
25+
<directory>tests/Integration/</directory>
26+
</testsuite>
27+
</testsuites>
28+
29+
<extensions>
30+
<bootstrap class="CakeDC\DbTest\Test\TestSuite\Fixture\SqliteExtension"/>
31+
</extensions>
32+
33+
<source>
34+
<include>
35+
<directory suffix=".php">src/</directory>
36+
</include>
37+
</source>
38+
</phpunit>

‎src/TestSuite/Fixture/Extension/PHPUnitAfterTestMethodFinishedSubscriber.php‎

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,6 @@
1212
*/
1313
namespace CakeDC\DbTest\TestSuite\Fixture\Extension;
1414

15-
use Cake\Database\Connection;
16-
use Cake\Datasource\ConnectionManager;
1715
use PHPUnit\Event\Test\AfterTestMethodFinished;
1816
use PHPUnit\Event\Test\AfterTestMethodFinishedSubscriber;
1917

@@ -22,14 +20,21 @@
2220
*/
2321
class PHPUnitAfterTestMethodFinishedSubscriber implements AfterTestMethodFinishedSubscriber
2422
{
23+
use TestConnectionTrait;
24+
25+
/**
26+
* @param \CakeDC\DbTest\TestSuite\Fixture\Extension\TransactionGuard $guard Transaction guard.
27+
*/
28+
public function __construct(private readonly TransactionGuard $guard = new TransactionGuard())
29+
{
30+
}
31+
2532
/**
2633
* @param \PHPUnit\Event\Test\AfterTestMethodFinished $event Event
2734
* @return void
2835
*/
2936
public function notify(AfterTestMethodFinished $event): void
3037
{
31-
$connection = ConnectionManager::get('test');
32-
assert($connection instanceof Connection);
33-
$connection->rollback();
38+
$this->guard->end($this->testConnection());
3439
}
3540
}

‎src/TestSuite/Fixture/Extension/PHPUnitExtension.php‎

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,9 @@ public function bootstrap(Configuration $configuration, Facade $facade, Paramete
3838
$facade->registerSubscribers(
3939
new PHPUnitStartedSubscriber($fixtureManager),
4040
new PHPUnitPreparationStartedSubscriber(),
41-
new PHPUnitAfterTestMethodFinishedSubscriber()
41+
new PHPUnitAfterTestMethodFinishedSubscriber(),
42+
new PHPUnitTestFinishedSubscriber(),
43+
new PHPUnitTestRunnerFinishedSubscriber()
4244
);
4345
}
4446
}

‎src/TestSuite/Fixture/Extension/PHPUnitPreparationStartedSubscriber.php‎

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,6 @@
1212
*/
1313
namespace CakeDC\DbTest\TestSuite\Fixture\Extension;
1414

15-
use Cake\Database\Connection;
16-
use Cake\Datasource\ConnectionManager;
1715
use PHPUnit\Event\Test\PreparationStarted;
1816
use PHPUnit\Event\Test\PreparationStartedSubscriber;
1917

@@ -28,18 +26,21 @@
2826
*/
2927
class PHPUnitPreparationStartedSubscriber implements PreparationStartedSubscriber
3028
{
29+
use TestConnectionTrait;
30+
31+
/**
32+
* @param \CakeDC\DbTest\TestSuite\Fixture\Extension\TransactionGuard $guard Transaction guard.
33+
*/
34+
public function __construct(private readonly TransactionGuard $guard = new TransactionGuard())
35+
{
36+
}
37+
3138
/**
3239
* @param \PHPUnit\Event\Test\PreparationStarted $event Event
3340
* @return void
3441
*/
3542
public function notify(PreparationStarted $event): void
3643
{
37-
$connection = ConnectionManager::get('test');
38-
assert($connection instanceof Connection);
39-
// a previous test may have left its transaction open (e.g. unmet requirements)
40-
if ($connection->inTransaction()) {
41-
$connection->rollback(true);
42-
}
43-
$connection->begin();
44+
$this->guard->begin($this->testConnection());
4445
}
4546
}

‎src/TestSuite/Fixture/Extension/PHPUnitStartedSubscriber.php‎

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@
2424
*/
2525
class PHPUnitStartedSubscriber implements StartedSubscriber
2626
{
27+
use TestConnectionTrait;
28+
2729
/**
2830
* @var true
2931
*/
@@ -35,9 +37,11 @@ class PHPUnitStartedSubscriber implements StartedSubscriber
3537

3638
/**
3739
* @param \CakeDC\DbTest\TestSuite\Fixture\FixtureManager $fixtureManager Fixture Manager instance
40+
* @param \CakeDC\DbTest\TestSuite\Fixture\Extension\TransactionGuard $guard Transaction guard.
3841
*/
3942
public function __construct(
40-
private readonly FixtureManager $fixtureManager
43+
private readonly FixtureManager $fixtureManager,
44+
private readonly TransactionGuard $guard = new TransactionGuard()
4145
) {
4246
}
4347

@@ -47,8 +51,7 @@ public function __construct(
4751
*/
4852
public function notify(Started $event): void
4953
{
50-
$connection = ConnectionManager::get('test');
51-
assert($connection instanceof Connection);
54+
$connection = $this->testConnection();
5255
$database = $connection->config();
5356

5457
try {
@@ -58,10 +61,10 @@ public function notify(Started $event): void
5861
$this->fixtureManager->setupDatabase($database, true, false);
5962
$ds = ConnectionManager::get('test');
6063
}
61-
assert($ds instanceof Connection);
64+
$ds = $this->asConnection($ds);
6265
// rollback transaction. gives us a 'fresh' copy of the database for the next
6366
// test suite to run
64-
$ds->rollback();
67+
$this->guard->end($ds);
6568

6669
if (!$this->databaseLoaded) {
6770
$this->loadDatabase($ds, $database);
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
<?php
2+
declare(strict_types=1);
3+
4+
/**
5+
* Copyright 2013 - 2023, Cake Development Corporation (https://www.cakedc.com)
6+
*
7+
* Licensed under The MIT License
8+
* Redistributions of files must retain the above copyright notice.
9+
*
10+
* @copyright Copyright 2013 - 2023, Cake Development Corporation (https://www.cakedc.com)
11+
* @license MIT License (http://www.opensource.org/licenses/mit-license.php)
12+
*/
13+
namespace CakeDC\DbTest\TestSuite\Fixture\Extension;
14+
15+
use PHPUnit\Event\Test\Finished;
16+
use PHPUnit\Event\Test\FinishedSubscriber;
17+
18+
/**
19+
* Closes the per-test transaction when the test finished.
20+
*
21+
* AfterTestMethodFinished is not emitted for test classes without after-test
22+
* hooks; Finished is emitted for every prepared test, so it covers that gap.
23+
*/
24+
class PHPUnitTestFinishedSubscriber implements FinishedSubscriber
25+
{
26+
use TestConnectionTrait;
27+
28+
/**
29+
* @param \CakeDC\DbTest\TestSuite\Fixture\Extension\TransactionGuard $guard Transaction guard.
30+
*/
31+
public function __construct(private readonly TransactionGuard $guard = new TransactionGuard())
32+
{
33+
}
34+
35+
/**
36+
* @param \PHPUnit\Event\Test\Finished $event Event
37+
* @return void
38+
*/
39+
public function notify(Finished $event): void
40+
{
41+
$this->guard->end($this->testConnection());
42+
}
43+
}

0 commit comments

Comments
 (0)