diff --git a/core/modules/simpletest/lib/Drupal/simpletest/TestBase.php b/core/modules/simpletest/lib/Drupal/simpletest/TestBase.php
index 8fb43bc..ed0398b 100644
--- a/core/modules/simpletest/lib/Drupal/simpletest/TestBase.php
+++ b/core/modules/simpletest/lib/Drupal/simpletest/TestBase.php
@@ -103,10 +103,17 @@
    */
   protected $setup = FALSE;
 
+  /**
+   * Indicates whether or not the database prefix has been set up for the test.
+   *
+   * This is checked in TestBase::tearDown() before deleting the tables of the
+   * test site. In case the database prefix was never set up properly this
+   * ensures that the tables of the parent site are not deleted.
+   *
+   * @var bool
+   */
   protected $setupDatabasePrefix = FALSE;
 
-  protected $setupEnvironment = FALSE;
-
   /**
    * TRUE if verbose debugging is enabled.
    *
@@ -788,31 +795,47 @@ public function run(array $methods = array()) {
       foreach ($class_methods as $method) {
         // If the current method starts with "test", run it - it's a test.
         if (strtolower(substr($method, 0, 4)) == 'test') {
-          // 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 . '()',
-          );
-          $completion_check_id = TestBase::insertAssert($this->testId, $class, FALSE, t('The test did not complete due to a fatal error.'), 'Completion check', $caller);
-          $this->setUp();
-          if ($this->setup) {
-            try {
-              $this->$method();
-              // Finish up.
-            }
-            catch (\Exception $e) {
-              $this->exceptionHandler($e);
-            }
+          try {
+            // 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 . '()',
+            );
+            $completion_check_id = TestBase::insertAssert($this->testId, $class, FALSE, t('The test did not complete due to a fatal error.'), 'Completion check', $caller);
+            $this->setUp();
+            $this->$method();
             $this->tearDown();
+            // Remove the completion check record.
+            TestBase::deleteAssert($completion_check_id);
+          }
+          catch (TestSetUpException $e) {
+            // Remove the completion check record.
+            TestBase::deleteAssert($completion_check_id);
+            $caller = array(
+              'file' => $e->getFile(),
+              'line' => $e->getLine(),
+            );
+            $message = $e->getMessage() ?: t("The test cannot be executed because it has not been set up properly.");
+            TestBase::insertAssert($this->testId, $class, FALSE, $message, 'Setup', $caller);
           }
-          else {
-            $this->fail(t("The test cannot be executed because it has not been set up properly."));
+          catch (TestTearDownException $e) {
+            // Remove the completion check record.
+            TestBase::deleteAssert($completion_check_id);
+            $caller = array(
+              'file' => $e->getFile(),
+              'line' => $e->getLine(),
+            );
+            $message = $e->getMessage() ?: t("The test could not be teared down properly.");
+            TestBase::insertAssert($this->testId, $class, FALSE, $message, 'Tear down', $caller);
+          }
+          catch (\Exception $e) {
+            // Remove the completion check record.
+            TestBase::deleteAssert($completion_check_id);
+            $this->exceptionHandler($e);
           }
-          // Remove the completion check record.
-          TestBase::deleteAssert($completion_check_id);
         }
       }
     }
@@ -866,12 +889,6 @@ protected function prepareDatabasePrefix() {
   protected function changeDatabasePrefix() {
     if (empty($this->databasePrefix)) {
       $this->prepareDatabasePrefix();
-      // If $this->prepareDatabasePrefix() failed to work, return without
-      // setting $this->setupDatabasePrefix to TRUE, so setUp() methods will
-      // know to bail out.
-      if (empty($this->databasePrefix)) {
-        return;
-      }
     }
 
     // Clone the current connection and replace the current prefix.
@@ -963,10 +980,21 @@ protected function prepareEnvironment() {
     $this->translation_files_directory = $this->public_files_directory . '/translations';
 
     // Create the directories
-    file_prepare_directory($this->public_files_directory, FILE_CREATE_DIRECTORY | FILE_MODIFY_PERMISSIONS);
-    file_prepare_directory($this->private_files_directory, FILE_CREATE_DIRECTORY);
-    file_prepare_directory($this->temp_files_directory, FILE_CREATE_DIRECTORY);
-    file_prepare_directory($this->translation_files_directory, FILE_CREATE_DIRECTORY);
+    $is_dir = is_dir('sites');
+    $is_readable = is_readable('sites');
+    $is_writable = is_writable('sites');
+    if (!file_prepare_directory($this->public_files_directory, FILE_CREATE_DIRECTORY | FILE_MODIFY_PERMISSIONS)) {
+      throw new TestSetUpException('Could not prepare the public files directory of the test site.');
+    };
+    if (!file_prepare_directory($this->private_files_directory, FILE_CREATE_DIRECTORY)) {
+      throw new TestSetUpException('Could not prepare the private files directory of the test site.');
+    }
+    if (!file_prepare_directory($this->temp_files_directory, FILE_CREATE_DIRECTORY)) {
+      throw new TestSetUpException('Could not prepare the temporary files directory of the test site.');
+    }
+    if (!file_prepare_directory($this->translation_files_directory, FILE_CREATE_DIRECTORY)) {
+      throw new TestSetUpException('Could not prepare the translation files directory of the test site.');
+    }
     $this->generatedTestFiles = FALSE;
 
     // Create and set new configuration directories.
@@ -1010,9 +1038,6 @@ protected function prepareEnvironment() {
     $test_info = &$GLOBALS['drupal_test_info'];
     $test_info['test_run_id'] = $this->databasePrefix;
     $test_info['in_child_site'] = FALSE;
-
-    // Indicate the environment was set up correctly.
-    $this->setupEnvironment = TRUE;
   }
 
   /**
@@ -1034,7 +1059,7 @@ protected function prepareConfigDirectories() {
       $GLOBALS['config_directories'][$type] = $path;
       // Ensure the directory can be created and is writeable.
       if (!install_ensure_config_directory($type)) {
-        return FALSE;
+        throw new TestSetUpException("Could not prepare the $type configuration directory of the test site.");
       }
       // Provide the already resolved path for tests.
       $this->configDirectories[$type] = $path;
diff --git a/core/modules/simpletest/lib/Drupal/simpletest/TestSetUpException.php b/core/modules/simpletest/lib/Drupal/simpletest/TestSetUpException.php
new file mode 100644
index 0000000..3b1dfb9
--- /dev/null
+++ b/core/modules/simpletest/lib/Drupal/simpletest/TestSetUpException.php
@@ -0,0 +1,14 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\simpletest\TestSetUpException.
+ */
+
+namespace Drupal\simpletest;
+
+/**
+ * An exception class for exceptions thrown during the set up of tests.
+ */
+class TestSetUpException extends \RuntimeException {
+}
diff --git a/core/modules/simpletest/lib/Drupal/simpletest/TestTearDownException.php b/core/modules/simpletest/lib/Drupal/simpletest/TestTearDownException.php
new file mode 100644
index 0000000..6a6c187
--- /dev/null
+++ b/core/modules/simpletest/lib/Drupal/simpletest/TestTearDownException.php
@@ -0,0 +1,14 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\simpletest\TestTearDownException.
+ */
+
+namespace Drupal\simpletest;
+
+/**
+ * An exception class for exceptions thrown during the set up of tests.
+ */
+class TestTearDownException extends \RuntimeException {
+}
diff --git a/core/modules/simpletest/lib/Drupal/simpletest/WebTestBase.php b/core/modules/simpletest/lib/Drupal/simpletest/WebTestBase.php
index a17e64b..e6a0536 100644
--- a/core/modules/simpletest/lib/Drupal/simpletest/WebTestBase.php
+++ b/core/modules/simpletest/lib/Drupal/simpletest/WebTestBase.php
@@ -732,9 +732,6 @@ protected function setUp() {
 
     // Prepare the environment for running tests.
     $this->prepareEnvironment();
-    if (!$this->setupEnvironment) {
-      return FALSE;
-    }
 
     // Reset all statics and variables to perform tests in a clean environment.
     $conf = array();
@@ -746,7 +743,7 @@ protected function setUp() {
     // write back to persistent caches when they are destructed.
     $this->changeDatabasePrefix();
     if (!$this->setupDatabasePrefix) {
-      return FALSE;
+      throw new TestSetUpException('The database prefix could not be changed for the test site.');
     }
 
     // After preparing the environment and changing the database prefix, we are
@@ -848,7 +845,6 @@ protected function setUp() {
     if (empty($path)) {
       _current_path('run-tests');
     }
-    $this->setup = TRUE;
   }
 
   /**
