VOOZH about

URL: https://deepwiki.com/hypervel/foundation/6.6-database-testing-utilities

⇱ Database Testing Utilities | hypervel/foundation | DeepWiki


Loading...
Last indexed: 7 February 2026 (101eff)
Menu

Database Testing Utilities

Purpose and Scope

This document covers the database testing utilities provided by Hypervel Foundation's testing framework. These utilities enable developers to write tests that interact with databases while maintaining proper isolation between test cases.

The database testing system provides three primary strategies for managing database state during tests:

  • RefreshDatabase: Migrates and rolls back the database between test runs
  • DatabaseMigrations: Runs migrations before tests execute
  • DatabaseTransactions: Wraps tests in database transactions

These strategies are implemented as traits that integrate with the test lifecycle through automatic detection and initialization. For information about the overall test lifecycle, see Test Case Foundation and Lifecycle. For other testing concerns, see Container and Service Testing and Authentication and Session Testing.

Sources: src/Testing/TestCase.php1-197


Database Testing Architecture

The database testing system integrates with the TestCase lifecycle through trait-based composition and automatic initialization. Each database strategy trait provides specific methods that are invoked during test setup and teardown phases.

Database Testing Trait Integration


Sources: src/Testing/TestCase.php24-197


Trait Detection and Initialization

The TestCase base class automatically detects and initializes database testing traits through the setUpTraits() method. This method uses PHP's reflection capabilities to discover which traits are in use and execute their corresponding setup methods.

Trait Detection Mechanism

Detection PhaseMethodLine Reference
Trait Discoveryclass_uses_recursive(static::class)src/Testing/TestCase.php82
RefreshDatabase Checkisset($uses[RefreshDatabase::class])src/Testing/TestCase.php84
DatabaseMigrations Checkisset($uses[DatabaseMigrations::class])src/Testing/TestCase.php88
DatabaseTransactions Checkisset($uses[DatabaseTransactions::class])src/Testing/TestCase.php92
Setup Method Invocation$this->{$method}()src/Testing/TestCase.php106
Teardown RegistrationbeforeApplicationDestroyed(fn() => ...)src/Testing/TestCase.php110

Trait Initialization Flow


Sources: src/Testing/TestCase.php80-115


RefreshDatabase Trait

The RefreshDatabase trait provides a testing strategy that ensures a clean database state by refreshing the database before each test. This trait is automatically detected and initialized when included in a test class.

Initialization Behavior

When the TestCase detects the RefreshDatabase trait during setup, it invokes the refreshDatabase() method:

Line 84-86 in TestCase.php:
if (isset($uses[RefreshDatabase::class])) {
 $this->refreshDatabase();
}

Use Cases

ScenarioRecommendation
Integration tests with database state changes✓ Recommended
Tests that need fresh migrations each run✓ Recommended
Fast unit tests without database interaction✗ Not needed
Tests requiring data to persist across test methods✗ Use DatabaseTransactions

Sources: src/Testing/TestCase.php84-86


DatabaseMigrations Trait

The DatabaseMigrations trait runs database migrations before test execution begins. This strategy is suitable for tests that require a migrated database schema but don't need to refresh the database between individual tests.

Initialization Behavior

When detected during test setup, the trait invokes the runDatabaseMigrations() method:

Line 88-90 in TestCase.php:
if (isset($uses[DatabaseMigrations::class])) {
 $this->runDatabaseMigrations();
}

Use Cases

ScenarioRecommendation
Test suite setup requiring schema✓ Recommended
Tests running against static test data✓ Recommended
Tests needing to verify migration behavior✓ Recommended
Tests requiring clean state between runs✗ Use RefreshDatabase

Sources: src/Testing/TestCase.php88-90


DatabaseTransactions Trait

The DatabaseTransactions trait wraps each test method in a database transaction. After the test completes, the transaction is rolled back, ensuring database state is not persisted between tests. This provides excellent test isolation with minimal performance overhead.

Initialization Behavior

The trait is detected and initialized with the beginDatabaseTransaction() method:

Line 92-94 in TestCase.php:
if (isset($uses[DatabaseTransactions::class])) {
 $this->beginDatabaseTransaction();
}

Transaction Lifecycle


Use Cases

ScenarioRecommendation
Fast tests with database changes✓ Recommended
Tests requiring isolation without migration overhead✓ Recommended
Multiple tests in same class sharing setup data✓ Recommended
Tests verifying transaction behavior✗ May interfere
Tests using nested transactions✗ Check database support

Sources: src/Testing/TestCase.php92-94


InteractsWithDatabase Trait

The InteractsWithDatabase trait provides the base functionality for database interaction during tests. This trait is automatically included in the TestCase base class and provides methods for database assertions and utilities.

Trait Composition

The TestCase includes InteractsWithDatabase as one of its core testing traits:

Line 13: use Hypervel\Foundation\Testing\Concerns\InteractsWithDatabase;
Line 30: use InteractsWithDatabase;

Integration with TestCase


Sources: src/Testing/TestCase.php13-30


Teardown and Cleanup

Database testing traits can register teardown methods that execute before the application is destroyed. This mechanism ensures proper cleanup of database state and resources.

Teardown Registration Mechanism

The trait detection system automatically discovers teardown methods using naming conventions:

Line 109-111 in TestCase.php:
if (method_exists($this, $method = 'tearDown' . class_basename($trait))) {
 $this->beforeApplicationDestroyed(fn () => $this->{$method}());
}

Teardown Execution Flow


Error Handling

Teardown callbacks are executed with error handling to ensure all callbacks run even if one fails:

BehaviorImplementationLine Reference
Exception Capturetry { $callback(); } catch (Throwable $e)src/Testing/TestCase.php180-186
First Exception Storedif (! $this->callbackException)src/Testing/TestCase.php183
Exception Re-thrownthrow $this->callbackExceptionsrc/Testing/TestCase.php132

Sources: src/Testing/TestCase.php109-111 src/Testing/TestCase.php117-152 src/Testing/TestCase.php177-188


Choosing the Right Database Testing Strategy

Different database testing strategies have different performance characteristics and use cases. The following comparison helps determine which trait to use.

Strategy Comparison

FeatureRefreshDatabaseDatabaseMigrationsDatabaseTransactions
Execution SpeedSlow (migrations run each test)Medium (migrations run once)Fast (rollback only)
Isolation LevelComplete (fresh database)Partial (shared schema)Complete (rolled back)
Setup OverheadHighMediumLow
Best ForIntegration testsTest suite setupUnit/feature tests
Multiple TestsEach test isolatedTests share stateEach test isolated
Database ChangesPersisted then resetPersisted across testsNever persisted

Decision Flow


Usage Examples

Fast Feature Tests:


Integration Tests:


Suite-Level Setup:


Sources: src/Testing/TestCase.php84-94


Coroutine Execution Context

Database testing methods are executed within coroutine context to ensure compatibility with Hyperf's async architecture. This is handled automatically by the TestCase infrastructure.

Coroutine Wrapping

All trait initialization occurs within a coroutine context:

Line 64-66 in TestCase.php:
$this->runInCoroutine(
 fn () => $this->setUpTraits()
);

The runInCoroutine() method ensures execution happens in a coroutine:

Line 193-196 in TestCase.php:
protected function runInCoroutine(callable $callback): void
{
 Coroutine::inCoroutine() ? $callback() : run($callback);
}

Implications for Database Testing

AspectBehavior
Database ConnectionsMust be coroutine-safe
Transaction IsolationBound to coroutine context
Connection PoolingHandled by Hyperf's async driver
Blocking OperationsAvoided through async I/O

Sources: src/Testing/TestCase.php64-66 src/Testing/TestCase.php193-196


Testing Best Practices

Trait Selection Guidelines

  1. Default Choice: Use DatabaseTransactions for most tests requiring database interaction
  2. Complex State: Use RefreshDatabase when tests create complex interdependent data
  3. Static Fixtures: Use DatabaseMigrations when tests read from pre-loaded fixtures
  4. Multiple Traits: Avoid using multiple database traits in the same test class

Performance Considerations

  • DatabaseTransactions provides the best performance for isolated tests
  • RefreshDatabase should be used sparingly due to migration overhead
  • Consider extracting non-database tests to separate classes for faster execution
  • Use in-memory databases (SQLite :memory:) for even faster test execution

Common Pitfalls

IssueSolution
Slow test suitePrefer DatabaseTransactions over RefreshDatabase
Tests affecting each otherEnsure proper trait usage and isolation
Transaction deadlocksCheck for nested transaction issues
Migration failuresVerify migrations are idempotent

Sources: src/Testing/TestCase.php80-115

Refresh this wiki

On this page