diff --git a/core/modules/simpletest/lib/Drupal/simpletest/TestBase.php b/core/modules/simpletest/lib/Drupal/simpletest/TestBase.php index 8e452d5..be6405f 100644 --- a/core/modules/simpletest/lib/Drupal/simpletest/TestBase.php +++ b/core/modules/simpletest/lib/Drupal/simpletest/TestBase.php @@ -208,6 +208,10 @@ public function __construct($test_id = NULL) { * - group: The human-readable name of the module ("Node", "Statistics"), or * the human-readable name of the Drupal facility tested (e.g. "Form API" * or "XML-RPC"). + * - regenerate-fixture: Either 'class' or 'method', defaults to 'method'. + * This allows you to specify whether to create a new Drupal instance per + * test class or test method. Historically, Drupal's SimpleTest has done + * this per method. */ public static function getInfo() { // PHP does not allow us to declare this method as abstract public static, @@ -817,7 +821,114 @@ public function run(array $methods = array()) { if (defined("$class::SORT_METHODS")) { sort($test_methods); } - foreach ($test_methods as $method) { + + $info = static::getInfo(); + if (isset($info['regenerate-fixture']) && $info['regenerate-fixture'] == 'class') { + $this->runFixturePerClass($test_methods); + } + else { + // Regenerate-fixture is empty or 'method' + foreach ($test_methods as $method) { + // Insert a fail record. This will be deleted on completion to ensure + // that testing completed. + $method_info = new \ReflectionMethod($class, $method); + $caller = array( + 'file' => $method_info->getFileName(), + 'line' => $method_info->getStartLine(), + 'function' => $class . '->' . $method . '()', + ); + $test_completion_check_id = TestBase::insertAssert($this->testId, $class, FALSE, 'The test did not complete due to a fatal error.', 'Completion check', $caller); + + try { + $this->prepareEnvironment(); + } + catch (\Exception $e) { + $this->exceptionHandler($e); + // The prepareEnvironment() method isolates the test from the parent + // Drupal site by creating a random database prefix and test site + // directory. If this fails, a test would possibly operate in the + // parent site. Therefore, the entire test run for this test class + // has to be aborted. + // restoreEnvironment() cannot be called, because we do not know + // where exactly the environment setup failed. + break; + } + + try { + $this->setUp(); + } + catch (\Exception $e) { + $this->exceptionHandler($e); + // Abort if setUp() fails, since all test methods will fail. + // But ensure to clean up and restore the environment, since + // prepareEnvironment() succeeded. + $this->restoreEnvironment(); + break; + } + try { + $this->$method(); + } + catch (\Exception $e) { + $this->exceptionHandler($e); + } + try { + $this->tearDown(); + } + catch (\Exception $e) { + $this->exceptionHandler($e); + // If a test fails to tear down, abort the entire test class, since + // it is likely that all tests will fail in the same way and a + // failure here only results in additional test artifacts that have + // to be manually deleted. + $this->restoreEnvironment(); + break; + } + + $this->restoreEnvironment(); + // Remove the test method completion check record. + TestBase::deleteAssert($test_completion_check_id); + } + } + + TestServiceProvider::$currentTest = NULL; + // Clear out the error messages and restore error handler. + drupal_get_messages(); + restore_error_handler(); + } + + private function runFixturePerClass($test_methods) { + $fail = FALSE; + // Regenerate-fixture is empty or 'method' + try { + $this->prepareEnvironment(); + } + catch (\Exception $e) { + $this->exceptionHandler($e); + $fail = TRUE; + // The prepareEnvironment() method isolates the test from the parent + // Drupal site by creating a random database prefix and test site + // directory. If this fails, a test would possibly operate in the + // parent site. Therefore, the entire test run for this test class + // has to be aborted. + // restoreEnvironment() cannot be called, because we do not know + // where exactly the environment setup failed. + } + + try { + $this->setUp(); + $fail = FALSE; + } + catch (\Exception $e) { + $this->exceptionHandler($e); + // Abort if setUp() fails, since all test methods will fail. + // But ensure to clean up and restore the environment, since + // prepareEnvironment() succeeded. + $this->restoreEnvironment(); + $fail = TRUE; + } + + if (!$fail) { + foreach ($test_methods as $method) { // Insert a fail record. This will be deleted on completion to ensure // that testing completed. $method_info = new \ReflectionMethod($class, $method); @@ -829,37 +940,12 @@ public function run(array $methods = array()) { $test_completion_check_id = TestBase::insertAssert($this->testId, $class, FALSE, 'The test did not complete due to a fatal error.', 'Completion check', $caller); try { - $this->prepareEnvironment(); - } - catch (\Exception $e) { - $this->exceptionHandler($e); - // The prepareEnvironment() method isolates the test from the parent - // Drupal site by creating a random database prefix and test site - // directory. If this fails, a test would possibly operate in the - // parent site. Therefore, the entire test run for this test class - // has to be aborted. - // restoreEnvironment() cannot be called, because we do not know - // where exactly the environment setup failed. - break; - } - - try { - $this->setUp(); - } - catch (\Exception $e) { - $this->exceptionHandler($e); - // Abort if setUp() fails, since all test methods will fail. - // But ensure to clean up and restore the environment, since - // prepareEnvironment() succeeded. - $this->restoreEnvironment(); - break; - } - try { $this->$method(); } catch (\Exception $e) { $this->exceptionHandler($e); } + } try { $this->tearDown(); } @@ -869,19 +955,12 @@ public function run(array $methods = array()) { // it is likely that all tests will fail in the same way and a // failure here only results in additional test artifacts that have // to be manually deleted. - $this->restoreEnvironment(); - break; } - - $this->restoreEnvironment(); - // Remove the test method completion check record. - TestBase::deleteAssert($test_completion_check_id); } - TestServiceProvider::$currentTest = NULL; - // Clear out the error messages and restore error handler. - drupal_get_messages(); - restore_error_handler(); + $this->restoreEnvironment(); + // Remove the test method completion check record. + TestBase::deleteAssert($test_completion_check_id); } /**