diff --git a/core/modules/simpletest/src/TestBase.php b/core/modules/simpletest/src/TestBase.php
index d414afc..5feca3b 100644
--- a/core/modules/simpletest/src/TestBase.php
+++ b/core/modules/simpletest/src/TestBase.php
@@ -9,8 +9,8 @@
 
 use Drupal\Component\Utility\Crypt;
 use Drupal\Component\Utility\Random;
-use Drupal\Core\Database\Database;
 use Drupal\Component\Utility\String;
+use Drupal\Core\Database\Database;
 use Drupal\Core\Config\ConfigImporter;
 use Drupal\Core\Config\StorageComparer;
 use Drupal\Core\DependencyInjection\ContainerBuilder;
@@ -246,6 +246,23 @@ protected function checkRequirements() {
   }
 
   /**
+   * Helper method to store an assertion record in the configured database.
+   *
+   * This method decouples database access from assertion logic.
+   *
+   * @param array $assertion
+   *   Keyed array representing an assertion, as generated by assert().
+   *
+   * @see self::assert()
+   */
+  protected function storeAssertion(array $assertion) {
+    return self::getDatabaseConnection()
+      ->insert('simpletest')
+      ->fields($assertion)
+      ->execute();
+  }
+
+  /**
    * Internal helper: stores the assert.
    *
    * @param $status
@@ -295,10 +312,7 @@ protected function assert($status, $message = '', $group = 'Other', array $calle
     );
 
     // Store assertion for display after the test has completed.
-    self::getDatabaseConnection()
-      ->insert('simpletest')
-      ->fields($assertion)
-      ->execute();
+    $this->storeAssertion($assertion);
 
     // We do not use a ternary operator here to allow a breakpoint on
     // test failure.
@@ -352,6 +366,7 @@ public static function insertAssert($test_id, $test_class, $status, $message = '
       'file' => $caller['file'],
     );
 
+    // We can't use storeAssertion() because this method is static.
     return self::getDatabaseConnection()
       ->insert('simpletest')
       ->fields($assertion)
@@ -370,6 +385,7 @@ public static function insertAssert($test_id, $test_class, $status, $message = '
    * @see \Drupal\simpletest\TestBase::insertAssert()
    */
   public static function deleteAssert($message_id) {
+    // We can't use storeAssertion() because this method is static.
     return (bool) self::getDatabaseConnection()
       ->delete('simpletest')
       ->condition('message_id', $message_id)
@@ -1231,7 +1247,6 @@ private function restoreEnvironment() {
    */
   public function errorHandler($severity, $message, $file = NULL, $line = NULL) {
     if ($severity & error_reporting()) {
-      require_once DRUPAL_ROOT . '/core/includes/errors.inc';
       $error_map = array(
         E_STRICT => 'Run-time notice',
         E_WARNING => 'Warning',
@@ -1266,7 +1281,6 @@ public function errorHandler($severity, $message, $file = NULL, $line = NULL) {
    * @see set_exception_handler
    */
   protected function exceptionHandler($exception) {
-    require_once DRUPAL_ROOT . '/core/includes/errors.inc';
     $backtrace = $exception->getTrace();
     $verbose_backtrace = $backtrace;
     // Push on top of the backtrace the call that generated the exception.
diff --git a/core/modules/simpletest/tests/src/Unit/TestBaseTest.php b/core/modules/simpletest/tests/src/Unit/TestBaseTest.php
index 9bac4fc..eb8556c 100644
--- a/core/modules/simpletest/tests/src/Unit/TestBaseTest.php
+++ b/core/modules/simpletest/tests/src/Unit/TestBaseTest.php
@@ -2,7 +2,7 @@
 
 /**
  * @file
- * Contains \Drupal\simpletest\TestBaseTest.
+ * Contains \Drupal\Tests\simpletest\Unit\TestBaseTest.
  */
 
 namespace Drupal\Tests\simpletest\Unit;
@@ -16,68 +16,504 @@
 class TestBaseTest extends UnitTestCase {
 
   /**
-   * A stub built using the TestBase class.
+   * Helper method for constructing a mock TestBase object.
    *
-   * @var \PHPUnit_Framework_MockObject_MockObject
+   * TestBase is abstract, so we have to mock it. We'll also
+   * mock the storeAssertion() method so we don't need the database.
+   *
+   * @param string $test_id
+   *   An identifying name for the mocked test.
+   *
+   * @return object
+   *   Mock of Drupal\simpletest\TestBase.
    */
-  protected $stub;
+  public function getTestBaseForAssertionTests($test_id) {
+    $mock_test_base = $this->getMockBuilder('Drupal\simpletest\TestBase')
+        ->setConstructorArgs(array($test_id))
+        ->setMethods(array('storeAssertion'))
+        ->getMockForAbstractClass();
+    // Override storeAssertion() so we don't need a database.
+    $mock_test_base->expects($this->any())
+        ->method('storeAssertion')
+        ->will($this->returnValue(NULL));
+    return $mock_test_base;
+  }
 
-  protected function setUp() {
-    $this->stub = $this->getMockForAbstractClass('Drupal\simpletest\TestBase');
+  /**
+   * Invoke methods that are protected or private.
+   *
+   * @param object $object
+   *   Object on which to invoke the method.
+   * @param string $method_name
+   *   Name of the method to invoke.
+   * @param array $arguments
+   *   Array of arguments to be passed to the method.
+   *
+   * @return mixed
+   *   Value returned by the invoked method.
+   */
+  public function invokeProtectedMethod($object, $method_name, array $arguments) {
+    $ref_method = new \ReflectionMethod($object, $method_name);
+    $ref_method->setAccessible(TRUE);
+    return $ref_method->invokeArgs($object, $arguments);
   }
 
   /**
    * Provides data for the random string validation test.
    *
    * @return array
-   *   An array of values passed to the test method.
+   *   - The expected result of the validation.
+   *   - The string to validate.
    */
-  public function randomStringValidateProvider () {
+  public function providerRandomStringValidate() {
     return array(
-      array(' curry paste', FALSE),
-      array('curry paste ', FALSE),
-      array('curry  paste', FALSE),
-      array('curry   paste', FALSE),
-      array('curry paste', TRUE),
-      array('thai green curry paste', TRUE),
-      array('@startswithat', FALSE),
-      array('contains@at', TRUE),
+      array(FALSE, ' curry paste'),
+      array(FALSE, 'curry paste '),
+      array(FALSE, 'curry  paste'),
+      array(FALSE, 'curry   paste'),
+      array(TRUE, 'curry paste'),
+      array(TRUE, 'thai green curry paste'),
+      array(FALSE, '@startswithat'),
+      array(TRUE, 'contains@at'),
     );
   }
 
   /**
-   * Tests the random strings validation rules.
-   *
-   * @param string $string
-   *   The string to validate.
-   * @param bool $expected
-   *   The expected result of the validation.
-   *
-   * @see \Drupal\simpletest\TestBase::randomStringValidate().
-   *
-   * @dataProvider randomStringValidateProvider
    * @covers ::randomStringValidate
+   * @dataProvider providerRandomStringValidate
    */
-  public function testRandomStringValidate($string, $expected) {
-    $actual = $this->stub->randomStringValidate($string);
+  public function testRandomStringValidate($expected, $string) {
+    $mock_test_base = $this->getMockForAbstractClass('Drupal\simpletest\TestBase');
+    $actual = $mock_test_base->randomStringValidate($string);
     $this->assertEquals($expected, $actual);
   }
 
   /**
-   * Tests that the random string contains a non-alphanumeric character.
-   *
-   * @see \Drupal\simpletest\TestBase::randomString().
+   * Provides data for testRandomString() and others.
    *
+   * @return array
+   *   - The number of items (characters, object properties) we expect any of
+   *     the random functions to give us.
+   */
+  public function providerRandomItems() {
+    return [
+      [NULL],
+      [0],
+      [1],
+      [2],
+      [3],
+      [4],
+      [7],
+    ];
+  }
+
+  /**
    * @covers ::randomString
+   * @dataProvider providerRandomItems
+   */
+  public function testRandomString($length) {
+    $mock_test_base = $this->getMockForAbstractClass('Drupal\simpletest\TestBase');
+    $string = $mock_test_base->randomString($length);
+    $this->assertEquals($length, strlen($string));
+    // randomString() should always include an ampersand ('&') if $length is
+    // greater than 2.
+    if ($length > 2) {
+      $this->assertContains('&', $string);
+    }
+  }
+
+  /**
+   * @covers ::randomObject
+   * @dataProvider providerRandomItems
+   */
+  public function testRandomObject($size) {
+    $test_base = $this->getTestBaseForAssertionTests('test_id');
+    // Note: count((array)object) works for now, maybe not later.
+    $this->assertEquals($size, count((array) $test_base->randomObject($size)));
+  }
+
+  /**
+   * @covers ::checkRequirements
+   */
+  public function testCheckRequirements() {
+    $test_base = $this->getTestBaseForAssertionTests('test_id');
+    $this->assertInternalType(
+        'array',
+        $this->invokeProtectedMethod($test_base, 'checkRequirements', array())
+    );
+  }
+
+  /**
+   * Data provider for testAssert().
+   *
+   * @return array
+   *   Standard dataProvider array of arrays:
+   *   - Expected result from assert().
+   *   - Expected status stored in TestBase->assertions.
+   *   - Status, passed to assert().
+   *   - Message, passed to assert().
+   *   - Group, passed to assert().
+   *   - Caller, passed to assert().
+   */
+  public function providerAssert() {
+    return array(
+      array(TRUE, 'pass', TRUE, 'Yay pass', 'test', array()),
+      array(FALSE, 'fail', FALSE, 'Boo fail', 'test', array()),
+      array(TRUE, 'pass', 'pass', 'Yay pass', 'test', array()),
+      array(FALSE, 'fail', 'fail', 'Boo fail', 'test', array()),
+      array(FALSE, 'exception', 'exception', 'Boo fail', 'test', array()),
+      array(FALSE, 'debug', 'debug', 'Boo fail', 'test', array()),
+    );
+  }
+
+  /**
+   * @covers ::assert
+   * @dataProvider providerAssert
+   */
+  public function testAssert($expected, $assertion_status, $status, $message, $group, $caller) {
+    $test_id = 'luke_i_am_your_' . $assertion_status;
+    $test_base = $this->getTestBaseForAssertionTests($test_id);
+
+    // Verify some startup values.
+    $this->assertAttributeEmpty('assertions', $test_base);
+    if (is_string($status)) {
+      $this->assertEquals(0, $test_base->results['#' . $status]);
+    }
+
+    // assert() is protected so we have to make it accessible.
+    $ref_assert = new \ReflectionMethod($test_base, 'assert');
+    $ref_assert->setAccessible(TRUE);
+
+    // Call assert() from within our hall of mirrors.
+    $this->assertEquals(
+        $expected,
+        $ref_assert->invokeArgs($test_base,
+          array($status, $message, $group, $caller)
+        )
+    );
+
+    // Check the side-effects of assert().
+    if (is_string($status)) {
+      $this->assertEquals(1, $test_base->results['#' . $status]);
+    }
+    $this->assertAttributeNotEmpty('assertions', $test_base);
+    // Make a ReflectionProperty for the assertions property,
+    // since it's protected.
+    $ref_assertions = new \ReflectionProperty($test_base, 'assertions');
+    $ref_assertions->setAccessible(TRUE);
+    $assertions = $ref_assertions->getValue($test_base);
+    $assertion = reset($assertions);
+    $this->assertEquals($assertion_status, $assertion['status']);
+    $this->assertEquals($test_id, $assertion['test_id']);
+    $this->assertEquals(get_class($test_base), $assertion['test_class']);
+    $this->assertEquals($message, $assertion['message']);
+    $this->assertEquals($group, $assertion['message_group']);
+  }
+
+  /**
+   * Data provider for assertTrue().
+   */
+  public function providerAssertTrue() {
+    return array(
+      array(TRUE, TRUE),
+      array(FALSE, FALSE),
+    );
+  }
+
+  /**
+   * @covers ::assertTrue
+   * @dataProvider providerAssertTrue
+   */
+  public function testAssertTrue($expected, $value) {
+    $test_base = $this->getTestBaseForAssertionTests('test_id');
+    $this->assertEquals(
+        $expected,
+        $this->invokeProtectedMethod($test_base, 'assertTrue', array($value))
+    );
+  }
+
+  /**
+   * @covers ::assertFalse
+   * @dataProvider providerAssertTrue
+   */
+  public function testAssertFalse($expected, $value) {
+    $test_base = $this->getTestBaseForAssertionTests('test_id');
+    $this->assertEquals(
+        (!$expected),
+        $this->invokeProtectedMethod($test_base, 'assertFalse', array($value))
+    );
+  }
+
+  /**
+   * Data provider for assertNull().
+   */
+  public function providerAssertNull() {
+    return array(
+      array(TRUE, NULL),
+      array(FALSE, ''),
+    );
+  }
+
+  /**
+   * @covers ::assertNull
+   * @dataProvider providerAssertNull
+   */
+  public function testAssertNull($expected, $value) {
+    $test_base = $this->getTestBaseForAssertionTests('test_id');
+    $this->assertEquals(
+        $expected,
+        $this->invokeProtectedMethod($test_base, 'assertNull', array($value))
+    );
+  }
+
+  /**
+   * @covers ::assertNotNull
+   * @dataProvider providerAssertNull
+   */
+  public function testAssertNotNull($expected, $value) {
+    $test_base = $this->getTestBaseForAssertionTests('test_id');
+    $this->assertEquals(
+        (!$expected),
+        $this->invokeProtectedMethod($test_base, 'assertNotNull', array($value))
+    );
+  }
+
+  /**
+   * Data provider for testAssertEqual().
+   */
+  public function providerAssertEqual() {
+    return array(
+      array(TRUE, 0, 0),
+      array(FALSE, 'foof', 'yay'),
+    );
+  }
+
+  /**
+   * @covers ::assertEqual
+   * @dataProvider providerAssertEqual
+   */
+  public function testAssertEqual($expected, $first, $second) {
+    $test_base = $this->getTestBaseForAssertionTests('test_id');
+    $this->assertEquals(
+        $expected,
+        $this->invokeProtectedMethod($test_base, 'assertEqual', array($first, $second))
+    );
+  }
+
+  /**
+   * @covers ::assertNotEqual
+   * @dataProvider providerAssertEqual
+   */
+  public function testAssertNotEqual($expected, $first, $second) {
+    $test_base = $this->getTestBaseForAssertionTests('test_id');
+    $this->assertEquals(
+        (!$expected),
+        $this->invokeProtectedMethod($test_base, 'assertNotEqual', array($first, $second))
+    );
+  }
+
+  /**
+   * Data provider for testAssertIdentical and testAssertNotIdentical().
+   */
+  public function providerAssertIdentical() {
+    return array(
+      array(TRUE, 0, 0),
+      array(FALSE, 'foof', 'yay'),
+    );
+  }
+
+  /**
+   * @covers ::assertIdentical
+   * @dataProvider providerAssertIdentical
+   */
+  public function testAssertIdentical($expected, $first, $second) {
+    $test_base = $this->getTestBaseForAssertionTests('test_id');
+    $this->assertEquals(
+        $expected,
+        $this->invokeProtectedMethod($test_base, 'assertIdentical', array($first, $second))
+    );
+  }
+
+  /**
+   * @covers ::assertNotIdentical
+   * @dataProvider providerAssertIdentical
+   */
+  public function testAssertNotIdentical($expected, $first, $second) {
+    $test_base = $this->getTestBaseForAssertionTests('test_id');
+    $this->assertEquals(
+        (!$expected),
+        $this->invokeProtectedMethod($test_base, 'assertNotIdentical', array($first, $second))
+    );
+  }
+
+  /**
+   * Data provider for testAssertIdenticalObject().
+   */
+  public function providerAssertIdenticalObject() {
+    $obj1 = new \stdClass();
+    $obj1->foof = 'yay';
+    $obj2 = $obj1;
+    $obj3 = clone $obj1;
+    $obj4 = new \stdClass();
+    return array(
+      array(TRUE, $obj1, $obj2),
+      array(TRUE, $obj1, $obj3),
+      array(FALSE, $obj1, $obj4),
+    );
+  }
+
+  /**
+   * @covers ::assertIdenticalObject
+   * @dataProvider providerAssertIdenticalObject
    */
-  public function testRandomString() {
-    $string = $this->stub->randomString(8);
-    $this->assertEquals(8, strlen($string));
-    $this->assertContains('&', $string);
+  public function testAssertIdenticalObject($expected, $first, $second) {
+    $test_base = $this->getTestBaseForAssertionTests('test_id');
+    $this->assertEquals(
+      $expected,
+      $this->invokeProtectedMethod($test_base, 'assertIdenticalObject', array($first, $second))
+    );
+  }
+
+  /**
+   * @covers ::pass
+   */
+  public function testPass() {
+    $test_base = $this->getTestBaseForAssertionTests('test_id');
+    $this->assertEquals(
+        TRUE,
+        $this->invokeProtectedMethod($test_base, 'pass', array())
+    );
+  }
+
+  /**
+   * @covers ::fail
+   */
+  public function testFail() {
+    $test_base = $this->getTestBaseForAssertionTests('test_id');
+    $this->assertEquals(
+        FALSE,
+        $this->invokeProtectedMethod($test_base, 'fail', array())
+    );
+  }
+
+  /**
+   * Data provider for testError().
+   *
+   * @return array
+   *   - Expected status for assertion.
+   *   - Group for use in assert().
+   */
+  public function providerError() {
+    return array(
+      array('debug', 'User notice'),
+      array('exception', 'Not User notice'),
+    );
+  }
+
+  /**
+   * @covers ::error
+   * @dataProvider providerError
+   */
+  public function testError($status, $group) {
+    // Mock up a TestBase object.
+    $mock_test_base = $this->getMockBuilder('Drupal\simpletest\TestBase')
+      ->setMethods(array('assert'))
+      ->getMockForAbstractClass();
+
+    // Set expectations for assert().
+    $mock_test_base->expects($this->once())
+      ->method('assert')
+      // The first argument to assert() should be the expected $status. This is
+      // the most important expectation of this test.
+      ->with($status)
+      // Arbitrary return value.
+      ->willReturn("$status:$group");
+
+    // Invoke error().
+    $this->assertEquals(
+        "$status:$group",
+        $this->invokeProtectedMethod($mock_test_base, 'error', array('msg', $group))
+    );
+  }
+
+  /**
+   * @covers ::getRandomGenerator
+   */
+  public function testGetRandomGenerator() {
+    $test_base = $this->getTestBaseForAssertionTests('test_id');
+    $this->assertInstanceOf(
+        'Drupal\Component\Utility\Random',
+        $this->invokeProtectedMethod($test_base, 'getRandomGenerator', array())
+    );
+  }
+
+  /**
+   * Provides data for testCopyConfig().
+   *
+   * @return array
+   *   - A keyed array which maps a key to a nested array.
+   */
+  public function providerCopyConfig() {
+    return [
+      [[]],
+      [['key' => ['value']]],
+      [['key' => ['value'], 'another_key' => ['another_value']]],
+    ];
+  }
+
+  /**
+   * @covers ::copyConfig
+   * @dataProvider providerCopyConfig
+   */
+  public function testCopyConfig($source_map) {
+    // Mock the target storage.
+    $mock_target_storage = $this->getMockBuilder('Drupal\Core\Config\StorageInterface')
+      ->setMethods(array('deleteAll', 'listAll', 'write', 'read'))
+      ->getMockForAbstractClass();
+    // Set method expectations. We always want deleteAll(), never want
+    // listAll(), never want read(), and expect the count of source storage for
+    // write().
+    $mock_target_storage->expects($this->once())
+      ->method('deleteAll');
+    $mock_target_storage->expects($this->never())
+      ->method('listAll');
+    $mock_target_storage->expects($this->exactly(count($source_map)))
+      ->method('write');
+    $mock_target_storage->expects($this->never())
+      ->method('read');
+
+    // Mock source storage.
+    $mock_source_storage = $this->getMockBuilder('Drupal\Core\Config\StorageInterface')
+      ->setMethods(array('deleteAll', 'listAll', 'write', 'read'))
+      ->getMockForAbstractClass();
+    // Set method expectations. These are backwards from $mock_target_storage.
+    // We never want deleteAll(), always want listAll(), never want write(),
+    // and expect the count of source storage for read().
+    $mock_source_storage->expects($this->never())
+      ->method('deleteAll');
+    $mock_source_storage->expects($this->once())
+      ->method('listAll')
+      // listAll() should return the keys of $source_map.
+      ->willReturnCallback(
+        function () use ($source_map) {
+          return array_keys($source_map);
+        }
+      );
+    $mock_source_storage->expects($this->never())
+      ->method('write');
+    $mock_source_storage->expects($this->exactly(count($source_map)))
+      ->method('read')
+      // read() should map a key to a value from $source_map.
+      ->willReturnCallback(
+        function ($key) use ($source_map) {
+          return $source_map[$key];
+        }
+      );
 
-    // Ensure that we can generate random strings with a length of 1.
-    $string = $this->stub->randomString(1);
-    $this->assertEquals(1, strlen($string));
+    // Exercise copyConfig(). Assert NULL because copyConfig() is void and only
+    // has side-effects.
+    $test_base = $this->getTestBaseForAssertionTests('test_id');
+    $this->assertNull($test_base->copyConfig($mock_source_storage, $mock_target_storage));
   }
 
 }
