如何删除Silverstripe SapphireTest运行YAML Fixture测试后遗留的临时数据库
Absolutely—you can absolutely add teardown logic to clean up those lingering temporary databases after running Sapphire tests with YAML fixtures, regardless of whether all tests pass or some fail. Let’s walk through how to implement this, including handling the tricky edge case where tests crash and abort the process mid-run (which is why you might see leftovers even when tests pass sometimes).
1. Use Sapphire’s Built-in teardown() Method
Sapphire’s base test class (SapphireTest) provides a teardown() method that runs after each test method completes—this is the first place to add your cleanup code.
Here’s how to implement it in your test class:
class MyCustomTest extends SapphireTest { protected static $fixture_file = 'fixtures/MyFixture.yml'; protected $tempDatabaseName; public function setUp() { parent::setUp(); // Capture the name of the temporary database created during setup $this->tempDatabaseName = DB::getConn()->getDatabaseName(); } public function teardown() { // Always run the parent teardown first to handle Sapphire's internal cleanup parent::teardown(); // Delete the temporary database if it exists if (!empty($this->tempDatabaseName)) { try { DB::dropDatabase($this->tempDatabaseName); } catch (Exception $e) { // Log the error if cleanup fails (optional but helpful) error_log("Failed to delete temporary database {$this->tempDatabaseName}: " . $e->getMessage()); } } } // Your test methods here... }
This will run cleanup after every individual test, even if a single test fails. But there’s a catch: if the test process crashes hard (e.g., a fatal error or uncaught exception that aborts PHP entirely), the teardown() method won’t fire. That’s where the next step comes in.
2. Add a Crash-Safe Shutdown Hook
To handle cases where the test process dies abruptly, you can register a PHP shutdown function that checks for leftover temporary databases and cleans them up. You can add this in your test bootstrap file or at the top of your test class:
// Register a shutdown function to clean up on process exit register_shutdown_function(function () { // Get all databases matching your test database naming pattern (adjust as needed) $databases = DB::getConn()->listDatabases(); $testDbPattern = '/^test_/'; // Assuming your temp DBs start with "test_" foreach ($databases as $dbName) { if (preg_match($testDbPattern, $dbName)) { try { DB::dropDatabase($dbName); } catch (Exception $e) { error_log("Shutdown cleanup failed for {$dbName}: " . $e->getMessage()); } } } });
Pro Tip: Use a Naming Convention
To avoid accidentally deleting non-test databases, make sure your temporary test databases follow a strict naming pattern (like test_ + a unique suffix). Sapphire often does this by default, but double-check your test configuration to confirm.
3. Verify with PHPUnit Suite Hooks
For broader cleanup across your entire test suite, you can use PHPUnit’s suite-level hooks. Add this to your phpunit.xml file:
<phpunit> <!-- ... other config ... --> <extensions> <extension class="MyTestSuiteCleanupExtension" /> </extensions> </phpunit>
Then create the extension class to run cleanup after the suite finishes:
class MyTestSuiteCleanupExtension extends PHPUnit\Runner\Extension\Extension { public function executeAfterSuite(PHPUnit\Runner\Extension\AfterSuiteHook $hook): void { // Same cleanup logic as the shutdown function here $databases = DB::getConn()->listDatabases(); $testDbPattern = '/^test_/'; foreach ($databases as $dbName) { if (preg_match($testDbPattern, $dbName)) { try { DB::dropDatabase($dbName); } catch (Exception $e) { error_log("Suite cleanup failed for {$dbName}: " . $e->getMessage()); } } } } }
This ensures that even if some tests crash, the entire suite’s cleanup still runs after all tests complete.
内容的提问来源于stack exchange,提问作者Avery Kushner

