diff --git a/core/includes/file.inc b/core/includes/file.inc
index 12737d3b40f49108ee7bf3a7d2fbe9eb220be9bf..f08070ec47b68917e5064c4fe9033b0eb606b239 100644
--- a/core/includes/file.inc
+++ b/core/includes/file.inc
@@ -199,12 +199,14 @@
  * @see hook_stream_wrappers_alter()
  */
 function file_get_stream_wrappers($filter = STREAM_WRAPPERS_ALL) {
-  $wrappers_storage = &drupal_static(__FUNCTION__);
+  $wrappers_storage = &drupal_static(__FUNCTION__, array());
 
-  if (!isset($wrappers_storage)) {
+  if (empty($wrappers_storage)) {
+    // Initialize $wrappers_storage, so that we are not calling this method
+    // repeatedly if no stream wrappers exist.
+    $wrappers_storage[STREAM_WRAPPERS_ALL] = array();
     $wrappers = array();
-    $container = \Drupal::getContainer();
-    if (is_object($container) && $container->has('module_handler')) {
+    if (\Drupal::hasService('module_handler')) {
       $wrappers = \Drupal::moduleHandler()->invokeAll('stream_wrappers');
       foreach ($wrappers as $scheme => $info) {
         // Add defaults.
diff --git a/core/modules/file/lib/Drupal/file/Tests/CopyTest.php b/core/modules/file/lib/Drupal/file/Tests/CopyTest.php
index 6ee9c9933a931b4eb0bddbe06e973ff1b1eaf48e..9fb0ed12a2c00c5a5a8a3985501de231c38c58da 100644
--- a/core/modules/file/lib/Drupal/file/Tests/CopyTest.php
+++ b/core/modules/file/lib/Drupal/file/Tests/CopyTest.php
@@ -10,7 +10,7 @@
 /**
  * Copy related tests.
  */
-class CopyTest extends FileManagedTestBase {
+class CopyTest extends FileManagedUnitTestBase {
   public static function getInfo() {
     return array(
       'name' => 'File copying',
diff --git a/core/modules/file/lib/Drupal/file/Tests/DeleteTest.php b/core/modules/file/lib/Drupal/file/Tests/DeleteTest.php
index 1f9e6c45a95d3f2a167481af8dd226bcb25e24b5..f345811e47325256f6dc3bb5f2bc650eebc11459 100644
--- a/core/modules/file/lib/Drupal/file/Tests/DeleteTest.php
+++ b/core/modules/file/lib/Drupal/file/Tests/DeleteTest.php
@@ -10,7 +10,7 @@
 /**
  * Deletion related tests.
  */
-class DeleteTest extends FileManagedTestBase {
+class DeleteTest extends FileManagedUnitTestBase {
   public static function getInfo() {
     return array(
       'name' => 'File delete',
diff --git a/core/modules/file/lib/Drupal/file/Tests/FileManagedUnitTestBase.php b/core/modules/file/lib/Drupal/file/Tests/FileManagedUnitTestBase.php
new file mode 100644
index 0000000000000000000000000000000000000000..324b1b5bf635bc7e5d0440241a41753b36c86583
--- /dev/null
+++ b/core/modules/file/lib/Drupal/file/Tests/FileManagedUnitTestBase.php
@@ -0,0 +1,216 @@
+<?php
+
+/**
+ * @file
+ * Contains Drupal\file\Tests\FileManagedUnitTestBase.
+ */
+
+namespace Drupal\file\Tests;
+
+use Drupal\file\FileInterface;
+use Drupal\simpletest\DrupalUnitTestBase;
+
+/**
+ * Base class for file unit tests that use the file_test module to test uploads and
+ * hooks.
+ */
+abstract class FileManagedUnitTestBase extends DrupalUnitTestBase {
+
+  /**
+   * Modules to enable.
+   *
+   * @var array
+   */
+  public static $modules = array('file_test', 'file', 'system', 'field', 'user');
+
+  function setUp() {
+    parent::setUp();
+    // Clear out any hook calls.
+    file_test_reset();
+
+    $this->installConfig(array('system'));
+    $this->installSchema('file', array('file_managed', 'file_usage'));
+    $this->installSchema('user', array('users', 'users_roles'));
+
+    // Make sure that a user with uid 1 exists, self::createFile() relies on
+    // it.
+    $user = entity_create('user', array('uid' => 1, 'name' => $this->randomName()));
+    $user->enforceIsNew();
+    $user->save();
+    $this->container->set('current_user', $user);
+  }
+
+  /**
+   * Assert that all of the specified hook_file_* hooks were called once, other
+   * values result in failure.
+   *
+   * @param $expected
+   *   Array with string containing with the hook name, e.g. 'load', 'save',
+   *   'insert', etc.
+   */
+  function assertFileHooksCalled($expected) {
+    \Drupal::state()->resetCache();
+
+    // Determine which hooks were called.
+    $actual = array_keys(array_filter(file_test_get_all_calls()));
+
+    // Determine if there were any expected that were not called.
+    $uncalled = array_diff($expected, $actual);
+    if (count($uncalled)) {
+      $this->assertTrue(FALSE, format_string('Expected hooks %expected to be called but %uncalled was not called.', array('%expected' => implode(', ', $expected), '%uncalled' => implode(', ', $uncalled))));
+    }
+    else {
+      $this->assertTrue(TRUE, format_string('All the expected hooks were called: %expected', array('%expected' => empty($expected) ? '(none)' : implode(', ', $expected))));
+    }
+
+    // Determine if there were any unexpected calls.
+    $unexpected = array_diff($actual, $expected);
+    if (count($unexpected)) {
+      $this->assertTrue(FALSE, format_string('Unexpected hooks were called: %unexpected.', array('%unexpected' => empty($unexpected) ? '(none)' : implode(', ', $unexpected))));
+    }
+    else {
+      $this->assertTrue(TRUE, 'No unexpected hooks were called.');
+    }
+  }
+
+  /**
+   * Assert that a hook_file_* hook was called a certain number of times.
+   *
+   * @param $hook
+   *   String with the hook name, e.g. 'load', 'save', 'insert', etc.
+   * @param $expected_count
+   *   Optional integer count.
+   * @param $message
+   *   Optional translated string message.
+   */
+  function assertFileHookCalled($hook, $expected_count = 1, $message = NULL) {
+    $actual_count = count(file_test_get_calls($hook));
+
+    if (!isset($message)) {
+      if ($actual_count == $expected_count) {
+        $message = format_string('hook_file_@name was called correctly.', array('@name' => $hook));
+      }
+      elseif ($expected_count == 0) {
+        $message = format_plural($actual_count, 'hook_file_@name was not expected to be called but was actually called once.', 'hook_file_@name was not expected to be called but was actually called @count times.', array('@name' => $hook, '@count' => $actual_count));
+      }
+      else {
+        $message = format_string('hook_file_@name was expected to be called %expected times but was called %actual times.', array('@name' => $hook, '%expected' => $expected_count, '%actual' => $actual_count));
+      }
+    }
+    $this->assertEqual($actual_count, $expected_count, $message);
+  }
+
+  /**
+   * Asserts that two files have the same values (except timestamp).
+   *
+   * @param \Drupal\file\FileInterface $before
+   *   File object to compare.
+   * @param \Drupal\file\FileInterface $after
+   *   File object to compare.
+   */
+  function assertFileUnchanged(FileInterface $before, FileInterface $after) {
+    $this->assertEqual($before->id(), $after->id(), t('File id is the same: %file1 == %file2.', array('%file1' => $before->id(), '%file2' => $after->id())), 'File unchanged');
+    $this->assertEqual($before->getOwner()->id(), $after->getOwner()->id(), t('File owner is the same: %file1 == %file2.', array('%file1' => $before->getOwner()->id(), '%file2' => $after->getOwner()->id())), 'File unchanged');
+    $this->assertEqual($before->getFilename(), $after->getFilename(), t('File name is the same: %file1 == %file2.', array('%file1' => $before->getFilename(), '%file2' => $after->getFilename())), 'File unchanged');
+    $this->assertEqual($before->getFileUri(), $after->getFileUri(), t('File path is the same: %file1 == %file2.', array('%file1' => $before->getFileUri(), '%file2' => $after->getFileUri())), 'File unchanged');
+    $this->assertEqual($before->getMimeType(), $after->getMimeType(), t('File MIME type is the same: %file1 == %file2.', array('%file1' => $before->getMimeType(), '%file2' => $after->getMimeType())), 'File unchanged');
+    $this->assertEqual($before->getSize(), $after->getSize(), t('File size is the same: %file1 == %file2.', array('%file1' => $before->getSize(), '%file2' => $after->getSize())), 'File unchanged');
+    $this->assertEqual($before->isPermanent(), $after->isPermanent(), t('File status is the same: %file1 == %file2.', array('%file1' => $before->isPermanent(), '%file2' => $after->isPermanent())), 'File unchanged');
+  }
+
+  /**
+   * Asserts that two files are not the same by comparing the fid and filepath.
+   *
+   * @param \Drupal\file\FileInterface $file1
+   *   File object to compare.
+   * @param \Drupal\file\FileInterface $file2
+   *   File object to compare.
+   */
+  function assertDifferentFile(FileInterface $file1, FileInterface $file2) {
+    $this->assertNotEqual($file1->id(), $file2->id(), t('Files have different ids: %file1 != %file2.', array('%file1' => $file1->id(), '%file2' => $file2->id())), 'Different file');
+    $this->assertNotEqual($file1->getFileUri(), $file2->getFileUri(), t('Files have different paths: %file1 != %file2.', array('%file1' => $file1->getFileUri(), '%file2' => $file2->getFileUri())), 'Different file');
+  }
+
+  /**
+   * Asserts that two files are the same by comparing the fid and filepath.
+   *
+   * @param \Drupal\file\FileInterface $file1
+   *   File object to compare.
+   * @param \Drupal\file\FileInterface $file2
+   *   File object to compare.
+   */
+  function assertSameFile(FileInterface $file1, FileInterface $file2) {
+    $this->assertEqual($file1->id(), $file2->id(), t('Files have the same ids: %file1 == %file2.', array('%file1' => $file1->id(), '%file2-fid' => $file2->id())), 'Same file');
+    $this->assertEqual($file1->getFileUri(), $file2->getFileUri(), t('Files have the same path: %file1 == %file2.', array('%file1' => $file1->getFileUri(), '%file2' => $file2->getFileUri())), 'Same file');
+  }
+
+  /**
+   * Create a file and save it to the files table and assert that it occurs
+   * correctly.
+   *
+   * @param $filepath
+   *   Optional string specifying the file path. If none is provided then a
+   *   randomly named file will be created in the site's files directory.
+   * @param $contents
+   *   Optional contents to save into the file. If a NULL value is provided an
+   *   arbitrary string will be used.
+   * @param $scheme
+   *   Optional string indicating the stream scheme to use. Drupal core includes
+   *   public, private, and temporary. The public wrapper is the default.
+   * @return \Drupal\file\FileInterface
+   *   File entity.
+   */
+  function createFile($filepath = NULL, $contents = NULL, $scheme = NULL) {
+    $file = new \stdClass();
+    $file->uri = $this->createUri($filepath, $contents, $scheme);
+    $file->filename = drupal_basename($file->uri);
+    $file->filemime = 'text/plain';
+    $file->uid = 1;
+    $file->created = REQUEST_TIME;
+    $file->changed = REQUEST_TIME;
+    $file->filesize = filesize($file->uri);
+    $file->status = 0;
+    // Write the record directly rather than using the API so we don't invoke
+    // the hooks.
+    $this->assertNotIdentical(drupal_write_record('file_managed', $file), FALSE, 'The file was added to the database.', 'Create test file');
+
+    return entity_create('file', (array) $file);
+  }
+
+  /**
+   * Creates a file and returns its URI.
+   *
+   * @param string $filepath
+   *   Optional string specifying the file path. If none is provided then a
+   *   randomly named file will be created in the site's files directory.
+   * @param string $contents
+   *   Optional contents to save into the file. If a NULL value is provided an
+   *   arbitrary string will be used.
+   * @param string $scheme
+   *   Optional string indicating the stream scheme to use. Drupal core includes
+   *   public, private, and temporary. The public wrapper is the default.
+   *
+   * @return string
+   *   File URI.
+   */
+  function createUri($filepath = NULL, $contents = NULL, $scheme = NULL) {
+    if (!isset($filepath)) {
+      // Prefix with non-latin characters to ensure that all file-related
+      // tests work with international filenames.
+      $filepath = 'Файл для тестирования ' . $this->randomName();
+    }
+    if (!isset($scheme)) {
+      $scheme = file_default_scheme();
+    }
+    $filepath = $scheme . '://' . $filepath;
+
+    if (!isset($contents)) {
+      $contents = "file_put_contents() doesn't seem to appreciate empty strings so let's put in some data.";
+    }
+
+    file_put_contents($filepath, $contents);
+    $this->assertTrue(is_file($filepath), t('The test file exists on the disk.'), 'Create test file');
+    return $filepath;
+  }
+
+}
diff --git a/core/modules/file/lib/Drupal/file/Tests/LoadTest.php b/core/modules/file/lib/Drupal/file/Tests/LoadTest.php
index 6a85e83eb1d8e11fe31d3592bb6b700f0e2e871a..bf6a1e935149b24497b1bb0efdb2df98cf60173a 100644
--- a/core/modules/file/lib/Drupal/file/Tests/LoadTest.php
+++ b/core/modules/file/lib/Drupal/file/Tests/LoadTest.php
@@ -10,7 +10,7 @@
 /**
  * Tests the file_load() function.
  */
-class LoadTest extends FileManagedTestBase {
+class LoadTest extends FileManagedUnitTestBase {
   public static function getInfo() {
     return array(
       'name' => 'File loading',
diff --git a/core/modules/file/lib/Drupal/file/Tests/MoveTest.php b/core/modules/file/lib/Drupal/file/Tests/MoveTest.php
index 8fb7b0771ae69b900c5e8aaf7c564d0b9f9bf27b..b063afa851092ce2746d70617c9b22ec3b60c2c5 100644
--- a/core/modules/file/lib/Drupal/file/Tests/MoveTest.php
+++ b/core/modules/file/lib/Drupal/file/Tests/MoveTest.php
@@ -10,7 +10,7 @@
 /**
  * Move related tests
  */
-class MoveTest extends FileManagedTestBase {
+class MoveTest extends FileManagedUnitTestBase {
   public static function getInfo() {
     return array(
       'name' => 'File moving',
diff --git a/core/modules/file/lib/Drupal/file/Tests/SaveDataTest.php b/core/modules/file/lib/Drupal/file/Tests/SaveDataTest.php
index 9b1bf2a20d301c277fcd6569a6d8444f9a724067..081b6b38c43f4712f2b0ea7239e7246c3545e926 100644
--- a/core/modules/file/lib/Drupal/file/Tests/SaveDataTest.php
+++ b/core/modules/file/lib/Drupal/file/Tests/SaveDataTest.php
@@ -10,7 +10,7 @@
 /**
  * Tests the file_save_data() function.
  */
-class SaveDataTest extends FileManagedTestBase {
+class SaveDataTest extends FileManagedUnitTestBase {
   public static function getInfo() {
     return array(
       'name' => 'File save data',
diff --git a/core/modules/file/lib/Drupal/file/Tests/SaveTest.php b/core/modules/file/lib/Drupal/file/Tests/SaveTest.php
index c2f0c38ba6776065a11287c302c90ec228ac3b0a..50d684754bb3bf01275792dc93c121dfc9d4cdb9 100644
--- a/core/modules/file/lib/Drupal/file/Tests/SaveTest.php
+++ b/core/modules/file/lib/Drupal/file/Tests/SaveTest.php
@@ -12,7 +12,7 @@
 /**
  * Tests saving files.
  */
-class SaveTest extends FileManagedTestBase {
+class SaveTest extends FileManagedUnitTestBase {
   public static function getInfo() {
     return array(
       'name' => 'File saving',
diff --git a/core/modules/file/lib/Drupal/file/Tests/SpaceUsedTest.php b/core/modules/file/lib/Drupal/file/Tests/SpaceUsedTest.php
index b98134bb15eb8c6ec3843b885fc2edb40f73c37c..49e57f8b721fd1db08c1b1c0e8e5dbeaa4def841 100644
--- a/core/modules/file/lib/Drupal/file/Tests/SpaceUsedTest.php
+++ b/core/modules/file/lib/Drupal/file/Tests/SpaceUsedTest.php
@@ -10,7 +10,7 @@
 /**
  *  This will run tests against the $file_managed->spaceUsed() function.
  */
-class SpaceUsedTest extends FileManagedTestBase {
+class SpaceUsedTest extends FileManagedUnitTestBase {
   public static function getInfo() {
     return array(
       'name' => 'File space used tests',
diff --git a/core/modules/file/lib/Drupal/file/Tests/UsageTest.php b/core/modules/file/lib/Drupal/file/Tests/UsageTest.php
index 713cc331e968a295516c95e96c26e414f5221f3c..3cff7da4108503882da3294b362cee0817039b87 100644
--- a/core/modules/file/lib/Drupal/file/Tests/UsageTest.php
+++ b/core/modules/file/lib/Drupal/file/Tests/UsageTest.php
@@ -10,7 +10,7 @@
 /**
  * Tests file usage functions.
  */
-class UsageTest extends FileManagedTestBase {
+class UsageTest extends FileManagedUnitTestBase {
   public static function getInfo() {
     return array(
       'name' => 'File usage',
@@ -161,7 +161,7 @@ function testTempFileCleanup() {
     $this->assertTrue(file_exists($perm_new->getFileUri()), 'New permanent file was created correctly.');
 
     // Run cron and then ensure that only the old, temp file was deleted.
-    $this->cronRun();
+    $this->container->get('cron')->run();
     $this->assertFalse(file_exists($temp_old->getFileUri()), 'Old temp file was correctly removed.');
     $this->assertTrue(file_exists($temp_new->getFileUri()), 'New temp file was correctly ignored.');
     $this->assertTrue(file_exists($perm_old->getFileUri()), 'Old permanent file was correctly ignored.');
diff --git a/core/modules/file/lib/Drupal/file/Tests/ValidateTest.php b/core/modules/file/lib/Drupal/file/Tests/ValidateTest.php
index 5656fdcbe7cd3067b9f4ee3384978c9e6c3b7393..59fa0146ac35fd7a52ffec5bc2b831523acaa055 100644
--- a/core/modules/file/lib/Drupal/file/Tests/ValidateTest.php
+++ b/core/modules/file/lib/Drupal/file/Tests/ValidateTest.php
@@ -10,7 +10,7 @@
 /**
  * Tests the file_validate() function.
  */
-class ValidateTest extends FileManagedTestBase {
+class ValidateTest extends FileManagedUnitTestBase {
   public static function getInfo() {
     return array(
       'name' => 'File validate',
diff --git a/core/modules/file/lib/Drupal/file/Tests/ValidatorTest.php b/core/modules/file/lib/Drupal/file/Tests/ValidatorTest.php
index 76abd8adcd1f95dddbae5a2e4d1b4e2b019060d6..8c45a76dea1b1091db5ae0bd59ec5f5fd766a499 100644
--- a/core/modules/file/lib/Drupal/file/Tests/ValidatorTest.php
+++ b/core/modules/file/lib/Drupal/file/Tests/ValidatorTest.php
@@ -10,7 +10,7 @@
 /**
  *  This will run tests against the file validation functions (file_validate_*).
  */
-class ValidatorTest extends FileManagedTestBase {
+class ValidatorTest extends FileManagedUnitTestBase {
   public static function getInfo() {
     return array(
       'name' => 'File validator tests',
@@ -129,12 +129,11 @@ function testFileValidateNameLength() {
    * Test file_validate_size().
    */
   function testFileValidateSize() {
-    $user = $this->container->get('current_user');
-    $original_user = $user;
-    drupal_save_session(FALSE);
-
     // Run these tests as a regular user.
-    $user = $this->drupalCreateUser();
+    $user = entity_create('user', array('uid' => 2, 'name' => $this->randomName()));
+    $user->enforceIsNew();
+    $user->save();
+    $this->container->set('current_user', $user);
 
     // Create a file with a size of 1000 bytes, and quotas of only 1 byte.
     $file = entity_create('file', array('filesize' => 1000));
@@ -146,8 +145,5 @@ function testFileValidateSize() {
     $this->assertEqual(count($errors), 1, 'Error for the user being over their limit.', 'File');
     $errors = file_validate_size($file, 1, 1);
     $this->assertEqual(count($errors), 2, 'Errors for both the file and their limit.', 'File');
-
-    $user = $original_user;
-    drupal_save_session(TRUE);
   }
 }
diff --git a/core/modules/simpletest/lib/Drupal/simpletest/DrupalUnitTestBase.php b/core/modules/simpletest/lib/Drupal/simpletest/DrupalUnitTestBase.php
index cab4b9ea1201daa08c54493d447d74b26a437a81..d10ce9f1a432e23edb179304abdac73e6db68421 100644
--- a/core/modules/simpletest/lib/Drupal/simpletest/DrupalUnitTestBase.php
+++ b/core/modules/simpletest/lib/Drupal/simpletest/DrupalUnitTestBase.php
@@ -179,6 +179,7 @@ protected function setUp() {
     // StreamWrapper APIs.
     // @todo Move StreamWrapper management into DrupalKernel.
     // @see https://drupal.org/node/2028109
+    $this->streamWrappers = array();
     // The public stream wrapper only depends on the file_public_path setting,
     // which is provided by UnitTestBase::setUp().
     $this->registerStreamWrapper('public', 'Drupal\Core\StreamWrapper\PublicStream');
@@ -197,8 +198,8 @@ protected function tearDown() {
     // of PHP core, which has to be maintained manually.
     // @todo Move StreamWrapper management into DrupalKernel.
     // @see https://drupal.org/node/2028109
-    foreach ($this->streamWrappers as $scheme) {
-      $this->unregisterStreamWrapper($scheme);
+    foreach ($this->streamWrappers as $scheme => $type) {
+      $this->unregisterStreamWrapper($scheme, $type);
     }
     parent::tearDown();
   }
@@ -417,7 +418,7 @@ protected function registerStreamWrapper($scheme, $class, $type = STREAM_WRAPPER
     if (isset($this->streamWrappers[$scheme])) {
       $this->unregisterStreamWrapper($scheme);
     }
-    $this->streamWrappers[$scheme] = $scheme;
+    $this->streamWrappers[$scheme] = $type;
     if (($type & STREAM_WRAPPERS_LOCAL) == STREAM_WRAPPERS_LOCAL) {
       stream_wrapper_register($scheme, $class);
     }
@@ -426,12 +427,14 @@ protected function registerStreamWrapper($scheme, $class, $type = STREAM_WRAPPER
     }
     // @todo Revamp Drupal's stream wrapper API for D8.
     // @see https://drupal.org/node/2028109
-    $wrappers = &drupal_static('file_get_stream_wrappers');
-    $wrappers[$scheme] = array(
+    $wrappers = &drupal_static('file_get_stream_wrappers', array());
+    $wrappers[STREAM_WRAPPERS_ALL][$scheme] = array(
       'type' => $type,
       'class' => $class,
     );
-    $wrappers[STREAM_WRAPPERS_ALL] = $wrappers;
+    if (($type & STREAM_WRAPPERS_WRITE_VISIBLE) == STREAM_WRAPPERS_WRITE_VISIBLE) {
+      $wrappers[STREAM_WRAPPERS_WRITE_VISIBLE][$scheme] = $wrappers[STREAM_WRAPPERS_ALL][$scheme];
+    }
   }
 
   /**
@@ -442,15 +445,20 @@ protected function registerStreamWrapper($scheme, $class, $type = STREAM_WRAPPER
    *
    * @param string $scheme
    *   The scheme to unregister.
+   * @param int $type
+   *   The Drupal Stream Wrapper API type of the scheme to unregister.
    */
-  protected function unregisterStreamWrapper($scheme) {
+  protected function unregisterStreamWrapper($scheme, $type) {
     stream_wrapper_unregister($scheme);
     unset($this->streamWrappers[$scheme]);
     // @todo Revamp Drupal's stream wrapper API for D8.
     // @see https://drupal.org/node/2028109
-    $wrappers = &drupal_static('file_get_stream_wrappers');
-    unset($wrappers[$scheme]);
-    unset($wrappers[STREAM_WRAPPERS_ALL][$scheme]);
+    $wrappers = &drupal_static('file_get_stream_wrappers', array());
+    foreach ($wrappers as $filter => $schemes) {
+      if (is_int($filter) && (($filter & $type) == $filter)) {
+        unset($wrappers[$filter][$scheme]);
+      }
+    }
   }
 
 }