diff --git a/core/lib/Drupal/Core/Test/TestDatabase.php b/core/lib/Drupal/Core/Test/TestDatabase.php
index a0121dc..d5f75f6 100644
--- a/core/lib/Drupal/Core/Test/TestDatabase.php
+++ b/core/lib/Drupal/Core/Test/TestDatabase.php
@@ -41,4 +41,50 @@ public static function getConnection() {
     return $connection;
   }
 
+  /**
+   * Store an assertion from outside the testing context.
+   *
+   * This is useful for inserting assertions that can only be recorded after
+   * the test case has been destroyed, such as PHP fatal errors. The caller
+   * information is not automatically gathered since the caller is most likely
+   * inserting the assertion on behalf of other code. In all other respects
+   * the method behaves just like \Drupal\simpletest\TestBase::assert() in terms
+   * of storing the assertion.
+   *
+   * @return
+   *   Message ID of the stored assertion.
+   *
+   * @see \Drupal\simpletest\TestBase::assert()
+   * @see \Drupal\simpletest\TestBase::deleteAssert()
+   */
+  public static function insertAssert($test_id, $test_class, $status, $message = '', $group = 'Other', array $caller = array()) {
+    // Convert boolean status to string status.
+    if (is_bool($status)) {
+      $status = $status ? 'pass' : 'fail';
+    }
+
+    $caller += array(
+      'function' => 'Unknown',
+      'line' => 0,
+      'file' => 'Unknown',
+    );
+
+    $assertion = array(
+      'test_id' => $test_id,
+      'test_class' => $test_class,
+      'status' => $status,
+      'message' => $message,
+      'message_group' => $group,
+      'function' => $caller['function'],
+      'line' => $caller['line'],
+      'file' => $caller['file'],
+    );
+
+    // We can't use storeAssertion() because this method is static.
+    return self::getConnection()
+      ->insert('simpletest')
+      ->fields($assertion)
+      ->execute();
+  }
+
 }
diff --git a/core/modules/simpletest/simpletest.module b/core/modules/simpletest/simpletest.module
index 751a729..7ead2da 100644
--- a/core/modules/simpletest/simpletest.module
+++ b/core/modules/simpletest/simpletest.module
@@ -9,7 +9,6 @@
 use Drupal\Core\Database\Database;
 use Drupal\Core\Render\Element;
 use Drupal\Core\Routing\RouteMatchInterface;
-use Drupal\simpletest\TestBase;
 use Drupal\Core\Test\TestDatabase;
 use Drupal\simpletest\TestDiscovery;
 use Symfony\Component\Process\PhpExecutableFinder;
@@ -530,11 +529,11 @@ function simpletest_log_read($test_id, $database_prefix, $test_class) {
           'line' => $match[4],
           'file' => $match[3],
         );
-        TestBase::insertAssert($test_id, $test_class, FALSE, $match[2], $match[1], $caller);
+        TestDatabase::insertAssert($test_id, $test_class, FALSE, $match[2], $match[1], $caller);
       }
       else {
         // Unknown format, place the entire message in the log.
-        TestBase::insertAssert($test_id, $test_class, FALSE, $line, 'Fatal error');
+        TestDatabase::insertAssert($test_id, $test_class, FALSE, $line, 'Fatal error');
       }
       $found = TRUE;
     }
@@ -679,7 +678,7 @@ function simpletest_clean_temporary_directories() {
     foreach ($files as $file) {
       if ($file[0] != '.') {
         $path = DRUPAL_ROOT . '/sites/simpletest/' . $file;
-        file_unmanaged_delete_recursive($path, array('Drupal\simpletest\TestBase', 'filePreDeleteCallback'));
+        file_unmanaged_delete_recursive($path, 'simpletest_temp_directory_pre_delete_callback');
         $count++;
       }
     }
@@ -845,3 +844,17 @@ function simpletest_phpunit_testcase_to_row($test_id, \SimpleXMLElement $testcas
   );
   return $record;
 }
+
+/**
+ * Ensures test files are deletable within file_unmanaged_delete_recursive().
+ *
+ * Some tests chmod generated files to be read only. During
+ * simpletest_clean_environment() and other cleanup operations, these files
+ * need to get deleted too.
+ *
+ * @param string $path
+ *   The path to be deleted.
+ */
+function simpletest_temp_directory_pre_delete_callback($path) {
+  chmod($path, 0700);
+}
diff --git a/core/modules/simpletest/src/TestBase.php b/core/modules/simpletest/src/TestBase.php
index 944810a..b3f8ee0 100644
--- a/core/modules/simpletest/src/TestBase.php
+++ b/core/modules/simpletest/src/TestBase.php
@@ -457,33 +457,7 @@ protected function assert($status, $message = '', $group = 'Other', array $calle
    * @see \Drupal\simpletest\TestBase::deleteAssert()
    */
   public static function insertAssert($test_id, $test_class, $status, $message = '', $group = 'Other', array $caller = array()) {
-    // Convert boolean status to string status.
-    if (is_bool($status)) {
-      $status = $status ? 'pass' : 'fail';
-    }
-
-    $caller += array(
-      'function' => 'Unknown',
-      'line' => 0,
-      'file' => 'Unknown',
-    );
-
-    $assertion = array(
-      'test_id' => $test_id,
-      'test_class' => $test_class,
-      'status' => $status,
-      'message' => $message,
-      'message_group' => $group,
-      'function' => $caller['function'],
-      'line' => $caller['line'],
-      'file' => $caller['file'],
-    );
-
-    // We can't use storeAssertion() because this method is static.
-    return self::getDatabaseConnection()
-      ->insert('simpletest')
-      ->fields($assertion)
-      ->execute();
+    return TestDatabase::insertAssert($test_id, $test_class, $status, $message, $group, $caller);
   }
 
   /**
@@ -969,7 +943,7 @@ public function run(array $methods = array()) {
         'file' => $object_info->getFileName(),
       );
       foreach ($missing_requirements as $missing_requirement) {
-        TestBase::insertAssert($this->testId, $class, FALSE, $missing_requirement, 'Requirements check', $caller);
+        TestDatabase::insertAssert($this->testId, $class, FALSE, $missing_requirement, 'Requirements check', $caller);
       }
       return;
     }
@@ -1028,7 +1002,7 @@ public function run(array $methods = array()) {
         '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);
+      $test_completion_check_id = TestDatabase::insertAssert($this->testId, $class, FALSE, 'The test did not complete due to a fatal error.', 'Completion check', $caller);
 
       try {
         $this->prepareEnvironment();
@@ -1537,7 +1511,7 @@ public static function generatePermutations($parameters) {
    * need to get deleted too.
    */
   public static function filePreDeleteCallback($path) {
-    chmod($path, 0700);
+    simpletest_temp_directory_pre_delete_callback($path);
   }
 
   /**
