samuelgfeller / test-traits
PHPUnit 测试特性集合
Requires
- php: ^8.2
- ext-pdo: *
Requires (Dev)
- friendsofphp/php-cs-fixer: ^3
- monolog/monolog: ^2 || ^3
- php-di/php-di: ^6 || ^7
- phpstan/phpstan: ^1
- phpunit/phpunit: ^10
- squizlabs/php_codesniffer: ^3
- symfony/mailer: ^5
README
这是 selective/test-traits 的一个副本,包含额外的测试特性,包括一个 fixture 特性,可以轻松插入与测试用例相关的自定义数据,以及一个 SQL 模式生成器,用于设置集成测试的测试数据库。
需求
- PHP 8.2+
- Composer
- PHPUnit 10+
安装
composer require samuelgfeller/test-traits --dev
文档
从 selective/test-traits 迁移
如果你一直在使用 selective/test-traits
包,并想迁移到这个库,以下函数需要重命名
- 函数
insertFixtures
(带 "s")现在为insertDefaultFixtureRecords
。 - 旧的
insertFixture
函数现在为insertFixtureRow
,而insertFixture
是另一个提供灵活方式插入具有可选自定义属性的 fixtures 的函数。
否则,特性是相同的,可以以相同的方式使用。此包将与 selective/test-traits
保持同步。
FixtureTestTrait
一个用于创建和插入具有可在测试函数中定义的数据的 fixtures 的特性。
提供的方法
/** * @param class-string $fixture * @param array $attributes */ protected function insertFixture(string $fixture, array $attributes = []): array
用法
// Inserts the fixture with the first_name being "Bob" and the rest default values from the fixture. // Returns the inserted row data with the auto-incremented id. $bobUserRow = $this->insertFixture(UserFixture::class, ['first_name' => 'Bob']);
Fixture
每个 fixture 都必须有一个属性 $table
,包含表名,以及一个数组 $records
,包含要插入的默认数据。
<?php namespace App\Test\Fixture; class UserFixture { // Database table name public string $table = 'user'; // Database records public array $records = [ // Only one record is relevant as the data is defined in the test function [ // The id 'id' => 1, 'first_name' => 'John', 'last_name' => 'Doe', ], ]; }
使用自定义属性插入 fixture
要定义应覆盖 fixture 类默认值的自定义数据,可以使用 insertFixture()
函数。
第一个参数是 fixture 完整限定类名,例如 UserFixture::class
,第二个(可选)是一个属性数组。
属性数组包含一行数据库的数据,例如:
['field_name' => 'value', 'other_field_name' => 'other_value']
.
可以将多个属性数组传递给函数,以插入具有不同数据的多个行,如下所示。
不需要在属性数组中指定表的所有字段。对于未指定的字段,将使用 fixture 的第一个 $records
条目的值。
该函数返回一个包含从 fixture 插入的数据的数组,包括自增的 id 或当传递多个行时,每行插入的数组。
<?php namespace App\Test\TestCase; use PHPUnit\Framework\TestCase; use TestTraits\Trait\FixtureTestTrait; final class FetchUsersTestAction extends TestCase { // ... use FixtureTestTrait; public function testAction(): void { // Insert the fixture with the default values $defaultUserRow = $this->insertFixture(UserFixture::class); // $defaultUserRow equals ['id' => 1, 'first_name' => 'John', 'last_name' => 'Doe'] // Insert the fixture with the given attributes $bobUserRow = $this->insertFixture(UserFixture::class, ['first_name' => 'Bob', ]); // $bobUserRow equals ['id' => 2, 'first_name' => 'Bob', 'last_name' => 'Doe'] // Insert 2 rows with the given attributes $jackAndAliceRows = $this->insertFixture( UserFixture::class, ['first_name' => 'Jack', 'last_name' => 'Brown'], ['first_name' => 'Alice'] ); // $jackAndAliceRows contains the two inserted rows: // [ // ['id' => 3, 'first_name' => 'Jack', 'last_name' => 'Brown'], // ['id' => 4, 'first_name' => 'Alice', 'last_name' => 'Doe'] // ] // Multiple rows can also be inserted when passing one attribute argument that contains // multiple arrays for each row $benAndEveRows = $this->insertFixture( UserFixture::class, [ ['first_name' => 'Jack', 'last_name' => 'Brown'], ['first_name' => 'Alice'] ] ); // ... } }
FixtureTestTrait
使用 DatabaseTestTrait
与数据库交互。
HttpTestTrait
需求
- 任何 PSR-7 和 PSR-17 工厂实现。
composer require nyholm/psr7-server
composer require nyholm/psr7
提供的方法
createRequest(string $method, $uri, array $serverParams = []): ServerRequestInterface
createFormRequest(string $method, $uri, array $data = null): ServerRequestInterface
createResponse(int $code = 200, string $reasonPhrase = ''): ResponseInterface
用法
<?php namespace App\Test\TestCase; use PHPUnit\Framework\TestCase; use TestTraits\Trait\ContainerTestTrait; use TestTraits\Trait\HttpTestTrait; class GetUsersTestAction extends TestCase { use ContainerTestTrait; use HttpTestTrait; public function test(): void { $request = $this->createRequest('GET', '/api/users'); $response = $this->app->handle($request); $this->assertSame(200, $response->getStatusCode()); } }
创建具有查询字符串参数的请求
$request = $this->createRequest('GET', '/api/users') ->withQueryParams($queryParams);
RouteTestTrait
Slim 4 框架路由测试特性。
需求
- Slim 4 框架应用
提供的方法
urlFor(string $routeName, array $data = [], array $queryParams = []): string
用法
<?php namespace App\Test\TestCase; use PHPUnit\Framework\TestCase; use TestTraits\Trait\ContainerTestTrait; use TestTraits\Trait\HttpTestTrait; use TestTraits\Trait\RouteTestTrait; final class GetUsersTestAction extends TestCase { use ContainerTestTrait; use HttpTestTrait; use RouteTestTrait; public function test(): void { $request = $this->createRequest('GET', $this->urlFor('get-users')); $response = $this->app->handle($request); $this->assertSame(200, $response->getStatusCode()); } }
使用命名路由和查询字符串参数创建请求
$request = $this->createRequest('GET', $this->urlFor('get-users')) ->withQueryParams($queryParams);
MailerTestTrait
需求:composer require symfony/mailer
DI 容器设置示例
use Symfony\Component\EventDispatcher\EventDispatcher; use Symfony\Component\EventDispatcher\EventDispatcherInterface; use Symfony\Component\Mailer\EventListener\EnvelopeListener; use Symfony\Component\Mailer\EventListener\MessageListener; use Symfony\Component\Mailer\EventListener\MessageLoggerListener; use Symfony\Component\Mailer\Mailer; use Symfony\Component\Mailer\MailerInterface; use Symfony\Component\Mailer\Transport; use Symfony\Component\Mailer\Transport\TransportInterface; // ... return [ // Mailer MailerInterface::class => function (ContainerInterface $container) { return new Mailer($container->get(TransportInterface::class)); }, // Mailer transport TransportInterface::class => function (ContainerInterface $container) { $settings = $container->get('settings')['smtp']; // smtp://user:pass@smtp.example.com:25 $dsn = sprintf( '%s://%s:%s@%s:%s', $settings['type'], $settings['username'], $settings['password'], $settings['host'], $settings['port'] ); $eventDispatcher = $container->get(EventDispatcherInterface::class); return Transport::fromDsn($dsn, $eventDispatcher); }, EventDispatcherInterface::class => function () { $eventDispatcher = new EventDispatcher(); $eventDispatcher->addSubscriber(new MessageListener()); $eventDispatcher->addSubscriber(new EnvelopeListener()); $eventDispatcher->addSubscriber(new MessageLoggerListener()); return $eventDispatcher; }, // ... ],
用法
PHPUnit 测试用例
<?php namespace App\Test\TestCase; use PHPUnit\Framework\TestCase; use TestTraits\Trait\ContainerTestTrait; use TestTraits\Trait\MailerTestTrait; use Symfony\Component\Mailer\MailerInterface; use Symfony\Component\Mime\Email; final class MailerExampleTest extends TestCase { use ContainerTestTrait; use MailerTestTrait; public function testMailer(): void { $mailer = $this->container->get(MailerInterface::class); // Send email $email = (new Email()) ->from('hello@example.com') ->to('you@example.com') ->subject('Time for Symfony Mailer!') ->text('Sending emails is fun again!') ->html('<p>My HTML content</p>'); $mailer->send($email); $this->assertEmailCount(1); $this->assertEmailTextBodyContains($this->getMailerMessage(), 'Sending emails is fun again!'); $this->assertEmailHtmlBodyContains($this->getMailerMessage(), '<p>My HTML content</p>'); } }
许可证
本项目采用MIT许可协议 — 详细信息请参阅许可文件。