Skip to content

Commit fd966a4

Browse files
author
Ondřej Ešler
committed
add support for attributes
1 parent 41b1ff5 commit fd966a4

File tree

7 files changed

+101
-52
lines changed

7 files changed

+101
-52
lines changed

README.md

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ Simple DB fixtures loading, replacement for phpunit/dbunit
44
## Usage
55
```php
66
use IW\PHPUnit\DbFixtures\DbFixturesTrait;
7+
use IW\PHPUnit\DbFixtures\Fixtures;
78

89
final class MyTest extends TestCase
910
{
@@ -17,10 +18,8 @@ final class MyTest extends TestCase
1718
'elastic' => new Elasticsearch\Client(...),
1819
};
1920
}
20-
21-
/**
22-
* @fixtures mysql read-only fixtures.yml
23-
*/
21+
22+
#[Fixtures('mysql', 'read-only', 'fixtures.yml')]
2423
public function testWithFixtures() {
2524
// before test data from fixtures.yml will be loaded into mysql
2625
}

composer.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,8 @@
1010
}
1111
],
1212
"require": {
13-
"php": ">=8.1",
14-
"phpunit/phpunit": "^9.5||^10.0||^11.0"
13+
"php": ">=8.3",
14+
"phpunit/phpunit": "^11.0"
1515
},
1616
"suggest": {
1717
"opensearch-project/opensearch-php" : "Needed for OpenSearch support",

docker-compose.yml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
version: '2'
21
services:
32
mysql:
43
image: mysql:8.0

src/DbFixturesTrait.php

Lines changed: 30 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,12 @@
77
use OpenSearch;
88
use PDO;
99
use stdClass;
10+
use ReflectionMethod;
1011
use Symfony\Component\Yaml\Yaml;
1112
use PHPUnit\Framework\Attributes\Before;
1213
use PHPUnit\Metadata\Annotation\Parser\Registry;
1314
use PHPUnit\Util\Test;
14-
15-
const AVAILABLE_MODES = ['read-only', 'write'];
15+
use PHPUnit\Event\Facade as EventFacade;
1616

1717
trait DbFixturesTrait
1818
{
@@ -40,44 +40,45 @@ abstract protected function getConnection(string $connectionName) : mixed;
4040
*/
4141
#[Before]
4242
public function loadFixturesByAnnotations(): void {
43-
if (method_exists(Test::class, 'parseTestMethodAnnotations')) {
44-
$annotations = $annotations = Test::parseTestMethodAnnotations(
45-
static::class,
46-
$this->getName(false)
47-
)['method'] ?? [];
48-
} else {
49-
$annotations = Registry::getInstance()->forMethod(
50-
static::class,
51-
$this->name()
52-
)->symbolAnnotations();
53-
}
43+
$annotations = Registry::getInstance()->forMethod(
44+
static::class,
45+
$this->name()
46+
)->symbolAnnotations();
5447

5548
$fixtures = [];
5649
foreach ($annotations['fixtures'] ?? [] as $fixture) {
57-
[$connectionName, $mode, $args] = \explode(' ', $fixture, 3) + [null, null, null];
50+
[$connectionName, $mode, $files] = \explode(' ', $fixture, 3) + [null, null, null];
5851

59-
if (!in_array($mode, AVAILABLE_MODES)) {
60-
throw new \UnexpectedValueException(
61-
sprintf('Wrong or missing mode of the fixture. Available modes [%s].', implode(', ', AVAILABLE_MODES))
62-
);
52+
$fixture = new Fixtures($connectionName, $mode, ...explode(' ', $files));
53+
54+
if (isset($fixtures[$connectionName])) {
55+
$fixture = $fixture->mergeWith($fixtures[$connectionName]);
6356
}
6457

65-
if (array_key_exists($connectionName, $fixtures)) {
66-
[$newMode, $newArgs] = $fixtures[$connectionName];
67-
$params = [$newMode, $newArgs.' '.$args];
68-
} else {
69-
$params = [$mode, $args];
58+
$fixtures[$connectionName] = $fixture;
59+
60+
EventFacade::emitter()->testTriggeredPhpunitDeprecation(
61+
$this->valueObjectForEvents(),
62+
'Annotation @fixtures is deprecated, use attribute Fixtures instead',
63+
);
64+
}
65+
66+
foreach ((new ReflectionMethod($this, $this->name()))->getAttributes(Fixtures::class) as $attribute) {
67+
$fixture = $attribute->newInstance();
68+
69+
if (isset($fixtures[$fixture->label])) {
70+
$fixture = $fixture->mergeWith($fixtures[$fixture->label]);
7071
}
7172

72-
$fixtures[$connectionName] = $params;
73+
$fixtures[$fixture->label] = $fixture;
7374
}
7475

75-
foreach ($fixtures as $connectionName => [$mode, $args]) {
76+
foreach ($fixtures as $connectionName => $fixture) {
77+
$mode = $fixture->mode;
78+
7679
$filenames = [];
77-
if ($args) {
78-
foreach (\explode(' ', $args) as $filename) {
79-
$filenames[] = $this->resolveFilePath($connectionName, $filename);
80-
}
80+
foreach ($fixture->files as $filename) {
81+
$filenames[] = $this->resolveFilePath($connectionName, $filename);
8182
}
8283

8384
$cache = $this->getCache();

src/Fixtures.php

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
<?php declare(strict_types=1);
2+
3+
namespace IW\PHPUnit\DbFixtures;
4+
5+
use Attribute;
6+
7+
#[Attribute(Attribute::TARGET_METHOD | Attribute::IS_REPEATABLE)]
8+
final readonly class Fixtures
9+
{
10+
public array $files;
11+
12+
public function __construct(public string $label, public string $mode, string ...$files) {
13+
assert(!empty($label), 'No label given');
14+
assert(in_array($mode, ['read-only', 'write']), 'Mode must be either "read-only" or "write"');
15+
assert(!empty($files), 'No fixture files given');
16+
17+
foreach ($files as $file) {
18+
assert(!empty($file), 'Empty fixture file given');
19+
}
20+
21+
$this->files = $files;
22+
}
23+
24+
public function mergeWith(Fixtures $fixtures) : Fixtures {
25+
assert($fixtures->label === $this->label, 'Cannot merge fixtures with different labels');
26+
27+
return new Fixtures(
28+
$this->label,
29+
in_array('write', [$fixtures->mode, $this->mode]) ? 'write' : 'read-only',
30+
array_values(array_unique(array_merge($fixtures->files, $this->files))),
31+
);
32+
}
33+
}

tests/FixturesTest.php

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
<?php declare(strict_types=1);
2+
3+
namespace IW\PHPUnit\DbFixtures;
4+
5+
use PHPUnit\Framework\TestCase;
6+
7+
final class FixturesTest extends TestCase
8+
{
9+
public function testCreate() : void {
10+
$fixtures = new Fixtures('mysql', 'write', 'foo.yaml', 'bar.json');
11+
12+
$this->assertSame('mysql', $fixtures->label);
13+
$this->assertSame('write', $fixtures->mode);
14+
$this->assertSame(['foo.yaml', 'bar.json'], $fixtures->files);
15+
}
16+
}

tests/UsageOfDbFixturesTraitTest.php

Lines changed: 17 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,11 @@
33
namespace IW\PHPUnit\DbFixtures;
44

55
use Elasticsearch;
6+
use IW\PHPUnit\DbFixtures\Fixtures;
67
use MongoDB;
7-
use PDO;
88
use MongoDB\Client;
9+
use PDO;
10+
use PHPUnit\Framework\Attributes\TestWith;
911

1012
final class UsageOfDbFixturesTraitTest extends \PHPUnit\Framework\TestCase
1113
{
@@ -52,6 +54,14 @@ public function provideConnections(): \Generator {
5254
* @testWith ["mysql"]
5355
* ["sqlite"]
5456
*/
57+
public function testBdsWithAnnotations(string $label): void {
58+
$this->testBds($label);
59+
}
60+
61+
#[Fixtures('mysql', 'read-only', 'bds.yml')]
62+
#[Fixtures('sqlite', 'read-only', 'bds.yml')]
63+
#[TestWith(['mysql'])]
64+
#[TestWith(['sqlite'])]
5565
public function testBds(string $connectionName): void {
5666
$connection = $this->getConnection($connectionName);
5767

@@ -76,10 +86,7 @@ public function testBds(string $connectionName): void {
7686
$this->assertSame($expected, $demo);
7787
}
7888

79-
/**
80-
* @fixtures mongo read-only bds.json
81-
*
82-
*/
89+
#[Fixtures('mongo', 'read-only', 'bds.json')]
8390
public function testBdsMongo(): void {
8491
$database = $this->getConnection('mongo');
8592
$fieldCollection = $database->selectCollection('user');
@@ -121,13 +128,10 @@ public function testBdsMongo(): void {
121128
$this->assertSame($expected, $foundDocuments);
122129
}
123130

124-
/**
125-
* @fixtures sqlite read-only bds.yml fixtures.yml fixtures.yaml
126-
* @fixtures mysql read-only bds.yml fixtures.yml fixtures.yaml
127-
*
128-
* @testWith ["mysql"]
129-
* ["sqlite"]
130-
*/
131+
#[Fixtures('mysql', 'read-only', 'bds.yml', 'fixtures.yml', 'fixtures.yaml')]
132+
#[Fixtures('sqlite', 'read-only', 'bds.yml', 'fixtures.yml', 'fixtures.yaml')]
133+
#[TestWith(['mysql'])]
134+
#[TestWith(['sqlite'])]
131135
public function testLoadingFixtures(string $connectionName): void {
132136
$connection = $this->getConnection($connectionName);
133137

@@ -152,10 +156,7 @@ public function testLoadingFixtures(string $connectionName): void {
152156
$this->assertSame($expected, $demo);
153157
}
154158

155-
/**
156-
* @fixtures mongo read-only fixtures.json
157-
*
158-
*/
159+
#[Fixtures('mongo', 'read-only', 'fixtures.json')]
159160
public function testLoadingFixturesMongo(): void {
160161
$database = $this->getConnection('mongo');
161162
$fieldCollection = $database->selectCollection('field');

0 commit comments

Comments
 (0)