Утилиты для тестирования пакетов и приложений на PhpSoftBox.
- В
tests/bootstrap.phpнастройте окружение и тестовое приложение:
use PhpSoftBox\Env\Environment;
use PhpSoftBox\TestUtils\TestApplication;
use PhpSoftBox\TestUtils\TestApplicationFactory;
$root = dirname(__DIR__);
$variables = Environment::create($root . '/config/env')
->setEnvironment('testing')
->setPrefix('APP_')
->includeGlobals(true)
->overload();
$variables->toGlobals(true);
$variables->toPutEnv(true);
$factory = new TestApplicationFactory(
basePath: $root,
env: 'testing',
);
TestApplication::configure($factory);
TestApplication::setFrozenTime('2024-01-01 00:00:00');- Используйте базовые тест-кейсы:
ApplicationTestCase— без HTTP клиента (подходит для консольных/сервисных тестов)WebTestCase— сTestHttpClient(интеграционные тесты контроллеров)
Пример WebTestCase:
use PhpSoftBox\TestUtils\WebTestCase;
use PhpSoftBox\TestUtils\TestApplication;
final class UsersTest extends WebTestCase
{
protected function container(): \Psr\Container\ContainerInterface
{
return TestApplication::container();
}
protected function bootApp(): void
{
TestApplication::boot();
}
protected function resetApp(): void
{
TestApplication::reset();
}
protected function app(): \PhpSoftBox\Application\Application
{
return TestApplication::app();
}
protected function session(): \PhpSoftBox\Session\SessionInterface
{
return TestApplication::container()->get(\PhpSoftBox\Session\SessionInterface::class);
}
protected function baseUri(): string
{
return 'https://example.test';
}
}Переключение режима БД на dump для дебага:
$this->databaseReloadMode = 'dump';Альтернатива для локального переключения релоадера (если вы хотите подменить сервис в контейнере):
$reloader = $this->container()->get(\PhpSoftBox\TestUtils\Database\DatabaseReloader::class);
$this->overrideContainer(
\PhpSoftBox\TestUtils\Database\DatabaseReloader::class,
$reloader->withMode('dump'),
);Если нужно централизованно настраивать запросы (например, прокидывать Request в контейнер, обновлять Redirector), зарегистрируйте конфигуратор:
use PhpSoftBox\TestUtils\Http\HttpClientConfiguratorInterface;
use Psr\Http\Message\ServerRequestInterface;
final class AppHttpClientConfigurator implements HttpClientConfiguratorInterface
{
public function configure(ServerRequestInterface $request): void
{
// кастомная логика
}
}Далее можно положить его в контейнер и WebTestCase автоматически подхватит:
$container->set(
HttpClientConfiguratorInterface::class,
new AppHttpClientConfigurator(),
);См. пример в examples/http-client-configurator.php.
- Inertia helpers (опционально):
use PhpSoftBox\TestUtils\Traits\InertiaTestTrait;
final class UsersTest extends WebTestCase
{
use InertiaTestTrait;
public function testIndexRenders(): void
{
$response = $this->httpClient()->get('/users');
$this->assertInertiaComponent($response, 'Admin/Users/Index');
$this->assertInertiaSnapshot($response, 'users-index', __DIR__ . '/../../local/tests/snapshots');
}
}examples/tests-bootstrap.php— базовыйtests/bootstrap.phpдля нового проекта.examples/http-client-configurator.php— пример конфигуратораTestHttpClient.
- По умолчанию используйте режим
transaction— он быстрее и стабильнее в CI. - Переключайте конкретный тест/класс на
dump, если нужно:- воспроизвести проблему с миграциями,
- проверить актуальность схемы,
- изолировать тест от «грязного» состояния.
- Если в тесте нужен другой режим или список подключений — переключайте только для этого класса, а не глобально.
- В больших наборах тестов старайтесь не смешивать
dumpиtransactionв одном процессе (меньше сюрпризов).
Пример использования с собственным базовым путём:
use PhpSoftBox\TestUtils\Snapshot\JsonSnapshotAssert;
use PhpSoftBox\TestUtils\Snapshot\SnapshotConfig;
$config = SnapshotConfig::forTestClass(
basePath: __DIR__ . '/../../local/tests/responses',
testClass: static::class,
)->withExcludedKeys(['meta.timestamp']);
$assert = new JsonSnapshotAssert();
$assert->assertMatchesSnapshot($payload, 'login-success', $config);DatabaseReloader пересоздаёт тестовые базы, копируя схему из основной базы.
Использует нативные CLI инструменты (mysqldump/mysql, pg_dump/psql, sqlite3),
поэтому ожидает их наличие в окружении тестов.
Доступны два режима: dump (по умолчанию) и transaction.
dump: пересоздаёт базу, затем грузит схему из дампа. Если указанdumpDirectory, дампы кэшируются по имени подключения/драйвера. Повторный прогон использует готовый файл. Для обновления схемы удалите файл дампа.transaction: не пересоздаёт базу. Вместо этого выполняетROLLBACKиBEGINна тестовой базе через переданный адаптер транзакций.
use PhpSoftBox\TestUtils\Database\DatabaseReloader;
use PhpSoftBox\TestUtils\Database\DatabaseReloaderConfig;
use PhpSoftBox\TestUtils\Database\DatabaseTransactionManager;
$config = DatabaseReloaderConfig::fromDatabaseConfig(
databaseConfig: $databaseConfig,
connectionNames: ['default', 'analytics'],
testSuffix: '_autotests',
dumpDirectory: __DIR__ . '/../../local/tests/dumps',
mode: 'dump',
);
$reloader = new DatabaseReloader($config);
$reloader->reloadAll();
$txConfig = DatabaseReloaderConfig::fromDatabaseConfig(
databaseConfig: $databaseConfig,
connectionNames: ['default'],
testSuffix: '_autotests',
mode: 'transaction',
);
$txReloader = new DatabaseReloader($txConfig, transactionAdapter: new DatabaseTransactionManager());
$txReloader->reloadAll();Используйте DatabaseConfigSwitcher, чтобы заменить DSN в конфиге приложения на тестовые DSN.
use PhpSoftBox\TestUtils\Database\DatabaseConfigSwitcher;
use PhpSoftBox\TestUtils\Database\DatabaseReloaderConfig;
$reloaderConfig = DatabaseReloaderConfig::fromDatabaseConfig($databaseConfig, ['default']);
$switcher = new DatabaseConfigSwitcher($reloaderConfig);
$testDatabaseConfig = $switcher->applyTestConfig($databaseConfig);Используйте Clock::freeze, чтобы фиксировать время в тестах.
use PhpSoftBox\Clock\Clock;
Clock::freeze(new \DateTimeImmutable('2024-01-02 03:04:05'));
$now = Clock::now();
Clock::reset();Используйте TestHttpClient, чтобы отправлять запросы в приложение без реального HTTP-транспорта:
use PhpSoftBox\TestUtils\Http\TestHttpClient;
$client = new TestHttpClient($app, $session, 'https://example.test');
$response = $client->post('/login', ['email' => 'demo@example.com']);