diff -u b/core/modules/simpletest/lib/Drupal/simpletest/TestBase.php b/core/modules/simpletest/lib/Drupal/simpletest/TestBase.php --- b/core/modules/simpletest/lib/Drupal/simpletest/TestBase.php +++ b/core/modules/simpletest/lib/Drupal/simpletest/TestBase.php @@ -784,6 +784,8 @@ // 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 { @@ -794,7 +796,7 @@ // Abort if setUp() fails, since all test methods will fail. // But ensure to clean up and restore the environment, since // prepareEnvironment() succeeded. - $this->tearDown(); + $this->restoreEnvironment(); break; } try { @@ -812,8 +814,10 @@ // 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 completion check record. TestBase::deleteAssert($completion_check_id); } @@ -905,13 +909,11 @@ * * Backups various current environment variables and resets them, so they do * not interfere with the Drupal site installation in which tests are executed - * and can be restored in TestBase::tearDown(). + * and can be restored in TestBase::restoreEnvironment(). * * Also sets up new resources for the testing environment, such as the public * filesystem and configuration directories. * - * @see TestBase::tearDown() - * * This method is private as it must only be called once by TestBase::run() * (multiple invocations for the same test would have unpredictable * consequences) and it must not be callable or overridable by test classes. @@ -1071,7 +1073,7 @@ * old module list. * * @see TestBase::prepareEnvironment() - * @see TestBase::tearDown() + * @see TestBase::restoreEnvironment() * * @todo Fix http://drupal.org/node/1708692 so that module enable/disable * changes are immediately reflected in \Drupal::getContainer(). Until then, @@ -1094,6 +1096,12 @@ /** * Performs cleanup tasks after each individual test method has been run. + */ + protected function tearDown() { + } + + /** + * Cleans up the test environment and restores the original environment. * * Deletes created files, database tables, and reverts environment changes. * @@ -1103,7 +1111,7 @@ * @see TestBase::changeDatabasePrefix() * @see TestBase::prepareEnvironment() */ - protected function tearDown() { + private function restoreEnvironment() { global $user, $conf; // Reset all static variables. @@ -1412,8 +1420,9 @@ /** * Ensures test files are deletable within file_unmanaged_delete_recursive(). * - * Some tests chmod generated files to be read only. During tearDown() and - * other cleanup operations, these files need to get deleted too. + * Some tests chmod generated files to be read only. During + * TestBase::restoreEnvironment() and other cleanup operations, these files + * need to get deleted too. */ public static function filePreDeleteCallback($path) { chmod($path, 0700); only in patch2: unchanged: --- a/core/lib/Drupal/Core/Utility/Error.php +++ b/core/lib/Drupal/Core/Utility/Error.php @@ -89,9 +89,12 @@ public static function decodeException(\Exception $exception) { */ public static function renderExceptionSafe(\Exception $exception) { $decode = static::decodeException($exception); + $backtrace = $decode['backtrace']; unset($decode['backtrace']); - return String::format('%type: !message in %function (line %line of %file).', $decode); + $output = String::format('%type: !message in %function (line %line of %file).', $decode); + $output .= '
' . static::formatBacktrace($backtrace) . '
'; + return $output; } /** only in patch2: unchanged: --- a/core/modules/simpletest/lib/Drupal/simpletest/Tests/BrokenSetUpTest.php +++ b/core/modules/simpletest/lib/Drupal/simpletest/Tests/BrokenSetUpTest.php @@ -46,41 +46,74 @@ function setUp() { } // If the test is being run from within simpletest, set up the broken test. else { - $this->pass(t('The test setUp() method has been run.')); - // Don't call parent::setUp(). This should trigger an error message. + if (file_get_contents($this->originalFileDirectory . '/simpletest/trigger') === 'setup') { + throw new \Exception('Broken setup'); + } + $this->pass('The setUp() method has run.'); } } function tearDown() { // If the test is being run from the main site, tear down normally. if (!drupal_valid_test_ua()) { + unlink($this->originalFileDirectory . '/simpletest/trigger'); parent::tearDown(); } + // If the test is being run from within simpletest, output a message. else { - // If the test is being run from within simpletest, output a message. - $this->pass(t('The tearDown() method has run.')); + if (file_get_contents($this->originalFileDirectory . '/simpletest/trigger') === 'teardown') { + throw new \Exception('Broken teardown'); + } + $this->pass('The tearDown() method has run.'); } } /** * Runs this test case from within the simpletest child site. */ - function testBreakSetUp() { + function testMethod() { // If the test is being run from the main site, run it again from the web // interface within the simpletest child site. if (!drupal_valid_test_ua()) { + // Verify that a broken setUp() method is caught. + file_put_contents($this->originalFileDirectory . '/simpletest/trigger', 'setup'); + $edit['Drupal\simpletest\Tests\BrokenSetUpTest'] = TRUE; + $this->drupalPostForm('admin/config/development/testing', $edit, t('Run tests')); + $this->assertRaw('Broken setup'); + $this->assertNoRaw('The setUp() method has run.'); + $this->assertNoRaw('Broken test'); + $this->assertNoRaw('The test method has run.'); + $this->assertNoRaw('Broken teardown'); + $this->assertNoRaw('The tearDown() method has run.'); + + // Verify that a broken tearDown() method is caught. + file_put_contents($this->originalFileDirectory . '/simpletest/trigger', 'teardown'); $edit['Drupal\simpletest\Tests\BrokenSetUpTest'] = TRUE; $this->drupalPostForm('admin/config/development/testing', $edit, t('Run tests')); + $this->assertNoRaw('Broken setup'); + $this->assertRaw('The setUp() method has run.'); + $this->assertNoRaw('Broken test'); + $this->assertRaw('The test method has run.'); + $this->assertRaw('Broken teardown'); + $this->assertNoRaw('The tearDown() method has run.'); - // Verify that the broken test and its tearDown() method are skipped. - $this->assertRaw(t('The test setUp() method has been run.')); - $this->assertRaw(t('The test cannot be executed because it has not been set up properly.')); - $this->assertNoRaw(t('The test method has run.')); - $this->assertNoRaw(t('The tearDown() method has run.')); + // Verify that a broken test method is caught. + file_put_contents($this->originalFileDirectory . '/simpletest/trigger', 'test'); + $edit['Drupal\simpletest\Tests\BrokenSetUpTest'] = TRUE; + $this->drupalPostForm('admin/config/development/testing', $edit, t('Run tests')); + $this->assertNoRaw('Broken setup'); + $this->assertRaw('The setUp() method has run.'); + $this->assertRaw('Broken test'); + $this->assertNoRaw('The test method has run.'); + $this->assertNoRaw('Broken teardown'); + $this->assertRaw('The tearDown() method has run.'); } // If the test is being run from within simpletest, output a message. else { - $this->pass(t('The test method has run.')); + if (file_get_contents($this->originalFileDirectory . '/simpletest/trigger') === 'test') { + throw new \Exception('Broken test'); + } + $this->pass('The test method has run.'); } } }