VOOZH about

URL: https://deepwiki.com/hypervel/testbench/5.1-bootstrapper-lifecycle

⇱ Bootstrapper Lifecycle | hypervel/testbench | DeepWiki


Loading...
Last indexed: 7 February 2026 (93289f)
Menu

Bootstrapper Lifecycle

Purpose and Scope

This document details the Bootstrapper::bootstrap() method and its complete lifecycle. The Bootstrapper class is responsible for one-time initialization of the testbench environment, including configuration loading, environment setup, constant definition, and ClassLoader initialization. This process occurs exactly once per test run, before any test cases execute.

For information about how the bootstrap process is triggered from TestCase, see Test Lifecycle and Hooks. For information about the testbench.yaml configuration structure, see Testbench Configuration (testbench.yaml). For information about file synchronization utilities, see File Synchronization with testbench-sync.


Bootstrap Method Overview

The Bootstrapper::bootstrap() method src/Bootstrapper.php21-40 serves as the single entry point for all environment initialization. This static method is idempotent and designed to be called once per test run by the TestCase class.

The method performs eight distinct operations in sequence:

  1. Configuration Loading: Parse testbench.yaml file
  2. Base Path Resolution: Determine the application base directory
  3. Constant Definition: Define BASE_PATH and SWOOLE_HOOK_FLAGS constants
  4. Environment Generation: Create .env file from YAML configuration
  5. Composer Lock Generation: Generate composer.lock for provider discovery
  6. Cleanup Registration: Register shutdown function for file purging
  7. ClassLoader Initialization: Initialize Hypervel ClassLoader with TestScanHandler

Sources: src/Bootstrapper.php21-40


Configuration Loading Phase

YAML File Discovery

The loadConfigFromYaml() method src/Bootstrapper.php80-96 implements a fallback mechanism for locating the configuration file. It searches for files in the following priority order:

  1. testbench.yaml
  2. testbench.yaml.example
  3. testbench.yaml.dist

The search is performed using a LazyCollection that filters for existing files:

$filename = LazyCollection::make(static function () use ($filename) {
 yield $filename;
 yield "{$filename}.example";
 yield "{$filename}.dist";
})->map(static function ($file) use ($workingPath) {
 return str_contains($file, DIRECTORY_SEPARATOR) ? $file : join_paths($workingPath, $file);
})->filter(static fn ($file) => is_file($file))
 ->first();

src/Bootstrapper.php82-89

Working Path Determination

The working path is determined by checking for the TESTBENCH_WORKING_PATH constant. If undefined, it defaults to the parent directory of the Bootstrapper class location:

$workingPath = defined('TESTBENCH_WORKING_PATH') ? TESTBENCH_WORKING_PATH : dirname(__DIR__)

src/Bootstrapper.php24

Configuration Storage

The parsed YAML content is stored in the static $config array property src/Bootstrapper.php17 using Symfony's YAML parser:

static::$config = Yaml::parseFile($filename) ?? [];

src/Bootstrapper.php95

Diagram: Configuration Loading Flow


Sources: src/Bootstrapper.php23-25 src/Bootstrapper.php80-96


Base Path Definition

Path Resolution Logic

After loading configuration, the bootstrap process determines the application base path. The resolution follows this priority:

  1. Custom Hypervel Path: If static::$config['hypervel'] is set in the YAML, use that path
  2. Default Workbench Path: Otherwise, use {workingPath}/workbench
$basePath = "{$workingPath}/workbench";
if (static::$config['hypervel'] ?? null) {
 $basePath = static::$config['hypervel'];
}

src/Bootstrapper.php27-30

Constant Definitions

Two critical constants are defined if they don't already exist:

ConstantPurposeDefault Value
BASE_PATHApplication root directory{workingPath}/workbench
SWOOLE_HOOK_FLAGSSwoole coroutine hook configurationSWOOLE_HOOK_ALL
! defined('BASE_PATH') && define('BASE_PATH', $basePath);
! defined('SWOOLE_HOOK_FLAGS') && define('SWOOLE_HOOK_FLAGS', SWOOLE_HOOK_ALL);

src/Bootstrapper.php32-33

The SWOOLE_HOOK_FLAGS constant configures Swoole to hook all blocking I/O operations, enabling Hyperf's coroutine functionality in the test environment.

Sources: src/Bootstrapper.php27-33


Environment File Generation

The generateEnv Method

The generateEnv() method src/Bootstrapper.php98-108 creates a .env file from the env array in the YAML configuration. This method:

  1. Checks if the env key exists in configuration
  2. If empty, returns early without creating a file
  3. Otherwise, joins the env array entries with PHP_EOL and writes to BASE_PATH/.env
if (! $env = static::$config['env'] ?? []) {
 return;
}

static::getFilesystem()->replace(
 join_paths(BASE_PATH, '/.env'),
 implode(PHP_EOL, $env)
);

src/Bootstrapper.php100-107

Example Configuration

Given this YAML configuration:


testbench.yaml4-5

The generated .env file will contain:

APP_NAME="Hypervel Testbench"

Filesystem Abstraction

The Bootstrapper uses a lazy-initialized Filesystem instance src/Bootstrapper.php47-54 from the Hypervel framework, providing cross-platform file operations.

Sources: src/Bootstrapper.php98-108 testbench.yaml4-5


Composer Lock Generation

Purpose and Structure

The generateComposerLock() method src/Bootstrapper.php56-78 creates a synthetic composer.lock file that enables Hypervel's package discovery system to locate configuration providers and service providers defined in testbench.yaml.

Generated Structure

The generated lock file contains a special hypervel-testbench package entry with metadata:


src/Bootstrapper.php58-71

Metadata Population

The extra.hypervel section is populated from three sources:

KeySourceMethod
configConfigProviderRegistergetConfigProviders()
providerstestbench.yamlstatic::$config['providers']
dont-discovertestbench.yamlstatic::$config['dont-discover']

The getConfigProviders() method src/Bootstrapper.php110-117 adds any custom config providers from the YAML and returns the complete provider list from ConfigProviderRegister.

Example from testbench.yaml


testbench.yaml1-2

This provider will be registered in the generated composer.lock file, making it discoverable by the Hypervel framework.

Sources: src/Bootstrapper.php56-78 src/Bootstrapper.php110-117 testbench.yaml1-2


Cleanup Registration

The registerPurgeFiles Method

The registerPurgeFiles() method src/Bootstrapper.php119-145 registers a PHP shutdown function that cleans up temporary files and directories after all tests complete.

Purge Configuration Structure

The purge configuration is defined in the YAML file under the purge key with two sub-arrays:


testbench.yaml13-19

Cleanup Logic

The shutdown function iterates through both lists and removes them relative to BASE_PATH:

register_shutdown_function(function () use ($files, $directories) {
 $filesystem = static::getFilesystem();
 foreach ($files as $file) {
 if (! $filesystem->exists($file = BASE_PATH . "/{$file}")) {
 continue;
 }
 $filesystem->delete($file);
 }

 foreach ($directories as $directory) {
 if (! $filesystem->exists($directory = BASE_PATH . "/{$directory}")) {
 continue;
 }
 $filesystem->deleteDirectory($directory);
 }
});

src/Bootstrapper.php129-144

Cleanup Timing

The cleanup occurs during PHP's shutdown phase, after all tests have completed and PHPUnit has finished execution. This ensures that generated files don't persist between test runs, maintaining a clean state.

Diagram: Purge Lifecycle


Sources: src/Bootstrapper.php119-145 testbench.yaml13-19


ClassLoader Initialization

TestScanHandler Integration

The final step of the bootstrap process initializes the Hypervel ClassLoader with a custom TestScanHandler:

ClassLoader::init(null, null, new TestScanHandler());

src/Bootstrapper.php39

Method Signature

The ClassLoader::init() method accepts three parameters:

  1. Application instance (null): Not needed during bootstrap
  2. Scan path (null): Uses default scanning behavior
  3. Scan handler (TestScanHandler): Customizes class discovery for testing environment

TestScanHandler Purpose

The TestScanHandler src/Bootstrapper.php10 is a specialized scan handler from Hypervel\Foundation\Testing that modifies the default class scanning behavior to work correctly in the test environment. It ensures that:

  • Test classes are properly discovered
  • Workbench classes are scanned correctly
  • The annotation cache works in the test context

Sources: src/Bootstrapper.php39 src/Bootstrapper.php9-10


Complete Bootstrap Flow

Diagram: Complete Bootstrap Sequence


Sources: src/Bootstrapper.php21-40


Filesystem Operations

Filesystem Singleton

The Bootstrapper uses a lazy-initialized Filesystem instance accessed through getFilesystem():

protected static function getFilesystem(): Filesystem
{
 if (static::$filesystem) {
 return static::$filesystem;
 }

 return static::$filesystem = new Filesystem();
}

src/Bootstrapper.php47-54

File Operations

The Filesystem class provides these methods used by the Bootstrapper:

MethodUsagePurpose
replace()Writing .env and composer.lockCreates or overwrites files
exists()Checking file/directory existenceUsed in purge cleanup
delete()Removing filesPurge individual files
deleteDirectory()Removing directoriesPurge entire directory trees

All file operations are performed relative to BASE_PATH after it's defined src/Bootstrapper.php32

Sources: src/Bootstrapper.php47-54 src/Bootstrapper.php104-107 src/Bootstrapper.php74-77 src/Bootstrapper.php131-143


Bootstrap Idempotency

Single Execution Guarantee

The bootstrap process is designed to execute exactly once per test run. The TestCase class ensures this by using a static flag that prevents multiple bootstrap calls. See Test Lifecycle and Hooks for implementation details.

State Persistence

The following state persists throughout the test run after bootstrap completes:

StateStorageLifetime
Configuration arraystatic::$configUntil process termination
Filesystem instancestatic::$filesystemUntil process termination
BASE_PATH constantGlobal constantUntil process termination
SWOOLE_HOOK_FLAGS constantGlobal constantUntil process termination
Generated .env fileFilesystemUntil purge at shutdown
Generated composer.lockFilesystemUntil purge at shutdown
Shutdown functionPHP runtimeExecutes once at shutdown

Diagram: Bootstrap State Lifetime


Sources: src/Bootstrapper.php17 src/Bootstrapper.php19 src/Bootstrapper.php32-33


Configuration Access

Public API

The Bootstrapper provides a public static method to access the loaded configuration:

public static function getConfig(): array
{
 return static::$config;
}

src/Bootstrapper.php42-45

This method allows other components (such as TestCase) to retrieve configuration values after bootstrap has completed. The returned array contains the complete parsed YAML structure.

Configuration Structure

Based on the example YAML file, the configuration array contains:

[
 'providers' => ['Workbench\App\Providers\WorkbenchServiceProvider'],
 'env' => ['APP_NAME="Hypervel Testbench"'],
 'workbench' => [
 'discovers' => [
 'web' => false,
 'api' => false,
 'commands' => false
 ]
 ],
 'purge' => [
 'files' => ['.env', 'composer.lock'],
 'directories' => ['runtime', 'public/vendor']
 ]
]

Sources: src/Bootstrapper.php42-45 testbench.yaml1-19


Error Handling

Missing Configuration File

If no YAML configuration file is found, the loadConfigFromYaml() method silently returns without populating static::$config. The bootstrap process continues with an empty configuration array.

if (is_null($filename)) {
 return;
}

src/Bootstrapper.php91-93

Empty Configuration

Each generation method checks for the presence of its required configuration keys:

This defensive approach ensures that the bootstrap process completes successfully even with minimal or missing configuration.

Sources: src/Bootstrapper.php91-93 src/Bootstrapper.php100 src/Bootstrapper.php125-127 src/Bootstrapper.php65-66


Integration with TestCase

The Bootstrapper::bootstrap() method is called from the TestCase::setUpBeforeClass() method, which executes once before any tests in the class run. For complete details on when and how bootstrap is triggered, see Test Lifecycle and Hooks.

The bootstrap process must complete before any application instances are created, as it defines critical constants (BASE_PATH, SWOOLE_HOOK_FLAGS) and generates files (.env, composer.lock) that the application depends on.

Sources: src/Bootstrapper.php21-40

Refresh this wiki

On this page