diff --git a/examples.module b/examples.module
index 87c3223..fe3fa72 100644
--- a/examples.module
+++ b/examples.module
@@ -56,6 +56,7 @@ function examples_toolbar() {
     'plugin_type_example' => 'plugin_type_example.description',
     'simpletest_example' => 'simpletest_example_description',
     'stream_wrapper_example' => 'stream_wrapper_example.description',
+    'testing_example' => 'testing_example.description',
     'queue_example' => 'queue_example',
     'tablesort_example' => 'tablesort_example_description',
     'tour_example' => 'tour_example_description',
diff --git a/testing_example/src/Controller/TestingExampleController.php b/testing_example/src/Controller/TestingExampleController.php
new file mode 100644
index 0000000..b7fa02a
--- /dev/null
+++ b/testing_example/src/Controller/TestingExampleController.php
@@ -0,0 +1,26 @@
+<?php
+
+namespace Drupal\testing_example\Controller;
+
+use Drupal\examples\Utility\DescriptionTemplateTrait;
+
+/**
+ * Controller for testing_example module.
+ *
+ * This class uses the DescriptionTemplateTrait to display text we put in the
+ * templates/description.html.twig file.  We render out the text via its
+ * description() method, and set up our routing to point to
+ * TestingExampleController::description().
+ */
+class TestingExampleController {
+
+  use DescriptionTemplateTrait;
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function getModuleName() {
+    return 'testing_example';
+  }
+
+}
diff --git a/testing_example/templates/description.html.twig b/testing_example/templates/description.html.twig
new file mode 100644
index 0000000..20d0e73
--- /dev/null
+++ b/testing_example/templates/description.html.twig
@@ -0,0 +1,79 @@
+{#
+
+Description text for the PHPUnit Example.
+
+#}
+
+{% trans %}
+<h2>Testing Frameworks in Drupal</h2>
+
+<h3>How to use this example module</h3>
+<p>You really should be reading the various docblocks in the files under
+  <code>tests/src/</code>.</p>
+
+<h3>How To:</h3>
+<ul>
+  <li>PHPUnit-based Drupal tests go in the <code>tests/src</code> directory, so
+    they will not be loaded by the autoloader during normal bootstrap.
+  </li>
+
+  <li>Unit tests go in <code>[your_module]/tests/src/Unit</code>.</li>
+  <li>Kernel tests go in <code>[your_module]/tests/src/Kernel</code>.</li>
+  <li>Functional tests go in <code>[your_module]/tests/src/Functional</code>.</li>
+</ul>
+
+<table>
+  <thead>
+  <tr>
+    <td><b>Type</b></td>
+    <td><b>Location</b></td>
+    <td><b>Namespace</b></td>
+    <td><b>Subclass of</b></td>
+  </tr>
+  </thead>
+  <tbody>
+  <tr>
+    <td>Unit Test</td>
+    <td>[your_module]/tests/src/Unit</td>
+    <td>Drupal\Tests\[your_module]\Unit\</td>
+    <td>Drupal\Tests\UnitTestCase</td>
+  </tr>
+  <tr>
+    <td>Kernel Test</td>
+    <td>[your_module]/tests/src/Kernel</td>
+    <td>Drupal\Tests\[your_module]\Kernel\</td>
+    <td>Drupal\KernelTests\KernelTestBase</td>
+  </tr>
+  <tr>
+    <td>Functional Test</td>
+    <td>[your_module]/tests/src/Functional</td>
+    <td>Drupal\Tests\[your_module]\Functional\</td>
+    <td>Drupal\Tests\BrowserTestBase</td>
+  </tr>
+  <tr>
+    <td>FunctionalJavascript Test</td>
+    <td>[your_module]/tests/src/FunctionalJavascript</td>
+    <td>Drupal\Tests\[your_module]\FunctionalJavascript\</td>
+    <td>Drupal\Tests\JavascriptTestBase</td>
+  </tr>
+  <tr>
+    <td>Shared Test Traits</td>
+    <td>[your_module]/tests/src/Traits</td>
+    <td>Drupal\Tests\[your_module]\Traits\</td>
+    <td>n/a</td>
+  </tr>
+
+  </tbody>
+</table>
+
+<h3>Standard PHPUnit Practices</h3>
+<p>You can run PHPUnit from the command line or via the run-tests.sh command.</p>
+<p>You can specify which type of test you're running via
+  <pre><code>phpunit --testsuite</code></pre> and
+  <pre><code>run-tests.sh --types</code><pre>.
+<p>There are many options to phpunit, but, for instance, to run all of the
+  testing_example phpunit tests, you could
+<pre><code>./vendor/phpunit/phpunit/phpunit -c core/ ./modules/examples/testing_example</code></pre>
+</p>
+
+{% endtrans %}
diff --git a/testing_example/testing_example.info.yml b/testing_example/testing_example.info.yml
new file mode 100644
index 0000000..07a6d52
--- /dev/null
+++ b/testing_example/testing_example.info.yml
@@ -0,0 +1,7 @@
+name: Testing example
+type: module
+description: Demonstrates Drupal core testing frameworks
+package: Example modules
+core: 8.x
+dependencies:
+  - examples:examples
diff --git a/testing_example/testing_example.links.menu.yml b/testing_example/testing_example.links.menu.yml
new file mode 100644
index 0000000..256d007
--- /dev/null
+++ b/testing_example/testing_example.links.menu.yml
@@ -0,0 +1,3 @@
+testing_example.description:
+  title: Testing Example
+  route_name: testing_example.description
diff --git a/testing_example/testing_example.module b/testing_example/testing_example.module
new file mode 100644
index 0000000..e44d99b
--- /dev/null
+++ b/testing_example/testing_example.module
@@ -0,0 +1,17 @@
+<?php
+
+/**
+ * @file
+ * Module file for testing_example.
+ */
+
+/**
+ * @defgroup testing_example Example: Testing
+ * @ingroup examples
+ * @{
+ * This example demonstrates Drupal 8 testing frameworks.
+ */
+
+/**
+ * @} End of "defgroup testing_example".
+ */
diff --git a/testing_example/testing_example.routing.yml b/testing_example/testing_example.routing.yml
new file mode 100644
index 0000000..5a684c6
--- /dev/null
+++ b/testing_example/testing_example.routing.yml
@@ -0,0 +1,7 @@
+# testing_example only has one route. It is to a page explaining the module.
+testing_example.description:
+  path: 'examples/testing-example'
+  defaults:
+    _controller: '\Drupal\testing_example\Controller\TestingExampleController::description'
+  requirements:
+    _permission: 'access content'
diff --git a/testing_example/tests/src/Functional/ExampleFunctionalTest.php b/testing_example/tests/src/Functional/ExampleFunctionalTest.php
new file mode 100644
index 0000000..417ff39
--- /dev/null
+++ b/testing_example/tests/src/Functional/ExampleFunctionalTest.php
@@ -0,0 +1,144 @@
+<?php
+
+namespace Drupal\Tests\testing_example\Functional;
+
+use Drupal\Tests\examples\Functional\ExamplesBrowserTestBase;
+
+/**
+ * Class ExampleFunctionalTest.
+ *
+ * You likely will want to see the various pages and forms navigated by this
+ * test. To do so, run PHPUnit with the equivalent of
+ *
+ * @code
+ * vendor/phpunit/phpunit/phpunit -c core/phpunit.xml --printer '\Drupal\Tests\Listeners\HtmlOutputPrinter' modules/examples/testing_example/tests/src/Functional
+ * @endcode
+ *
+ * @group testing_example
+ * @group examples
+ */
+class ExampleFunctionalTest extends ExamplesBrowserTestBase {
+
+  /**
+   * {@inheritdoc}
+   */
+  public static $modules = [
+    'node',
+    'filter',
+    'field',
+    'text',
+    'system',
+    'options',
+    'user',
+  ];
+
+  protected $adminUser;
+
+  protected $authUser;
+
+  /**
+   * SetUp() happens for *every* test, so commonalities should go here.
+   */
+  protected function setUp() {
+    parent::setUp();
+
+    // Create users.
+    $this->adminUser = $this->drupalCreateUser([
+      'access administration pages',
+      'view the administration theme',
+      'administer permissions',
+      'administer nodes',
+      'administer content types',
+    ]);
+    $this->authUser = $this->drupalCreateUser([], 'authuser');
+
+    // We have to create a content type because testing uses the 'testing'
+    // profile, which has no content types by default.
+    // Although we could have visited admin pages and pushed buttons to create
+    // the content type, there happens to be function we can use in this case.
+    $this->createContentType(['type' => 'test_content_type']);
+  }
+
+  /**
+   * Demonstrate node creation via button-pushing.
+   */
+  public function testNewPage() {
+    $this->drupalLogin($this->adminUser);
+
+    $assert = $this->assertSession();
+
+    $this->drupalGet('node/add/test_content_type');
+    $assert->statusCodeEquals(200);
+
+    $nodeTitle = 'Test node for testNewPage';
+    $edit = [
+      'title[0][value]' => $nodeTitle,
+      'body[0][value]' => 'Body of test node',
+    ];
+    $this->drupalPostForm(NULL, $edit, 'op');
+    $assert->statusCodeEquals(200);
+    $assert->linkExists($nodeTitle);
+
+    // Log in our normal user and navigate to the node.
+    $this->drupalLogin($this->authUser);
+
+    /** @var \Drupal\node\NodeInterface $createdNode */
+    $createdNode = $this->drupalGetNodeByTitle($nodeTitle);
+    $url = $createdNode->toUrl();
+    $this->drupalGet($url);
+    $assert->statusCodeEquals(200);
+
+    // Look at the *page* title.
+    $assert->titleEquals("{$nodeTitle} | Drupal");
+
+    // Find the title of the node itself.
+    $nodeTitleElement = $this->getSession()
+      ->getPage()
+      ->find('css', 'h1 span.field--name-title');
+    $this->assertEquals($nodeTitleElement->getText(), $nodeTitle);
+  }
+
+  /**
+   * Demonstrate node creation via NodeCreationTrait::createNode.
+   */
+  public function testNewPageAPICreate() {
+    $assert = $this->assertSession();
+
+    $this->drupalLogin($this->adminUser);
+
+    $nodeTitle = 'Test node for testNewPageAPICreate';
+
+    // Create new node using API.
+    $node = $this->drupalCreateNode([
+      'type' => 'test_content_type', // Default value: page.
+      'title' => $nodeTitle,
+      'body' => [
+        [
+          'format' => filter_default_format($this->adminUser),
+          'value' => 'Body of test node',
+        ],
+      ],
+    ]);
+    $node->save();
+    $url = $node->toUrl();
+
+    // Confirm page creation.
+    $this->drupalGet($url);
+    $assert->statusCodeEquals(200);
+
+    // Log in our normal user and navigate to the node.
+    $this->drupalLogin($this->authUser);
+    $this->drupalGet($url);
+    $assert->statusCodeEquals(200);
+
+    // Look at the *page* title.
+    $assert->titleEquals("{$nodeTitle} | Drupal");
+
+    // Find the title of the node itself.
+    $nodeTitleElement = $this->getSession()
+      ->getPage()
+      ->find('css', 'h1 span.field--name-title');
+    $this->assertEquals($nodeTitleElement->getText(), $nodeTitle);
+  }
+
+}
diff --git a/testing_example/tests/src/Functional/TestingExampleMenuTest.php b/testing_example/tests/src/Functional/TestingExampleMenuTest.php
new file mode 100644
index 0000000..35bfb8f
--- /dev/null
+++ b/testing_example/tests/src/Functional/TestingExampleMenuTest.php
@@ -0,0 +1,49 @@
+<?php
+
+namespace Drupal\Tests\testing_example\Functional;
+
+use Drupal\Tests\BrowserTestBase;
+
+/**
+ * Test the user-facing menus in Testing Example.
+ *
+ * Note that this is not an example test. We use this test to verify that
+ * testing_example's links and routes all work.
+ *
+ * @ingroup testing_example
+ *
+ * @group testing_example
+ * @group examples
+ */
+class TestingExampleMenuTest extends BrowserTestBase {
+
+  /**
+   * Modules to enable.
+   *
+   * @var array
+   */
+  public static $modules = ['testing_example'];
+
+  /**
+   * The installation profile to use with this test.
+   *
+   * We need the 'minimal' profile in order to make sure the Tool block is
+   * available.
+   *
+   * @var string
+   */
+  protected $profile = 'minimal';
+
+  /**
+   * Verify and validate that default menu links were loaded for this module.
+   */
+  public function testTestingNavigation() {
+    foreach (['' => '/examples/testing-example'] as $page => $path) {
+      $this->drupalGet($page);
+      $this->assertLinkByHref($path);
+    }
+    $this->drupalGet('/examples/testing-example');
+    $this->assertResponse(200, 'Description page exists.');
+  }
+
+}
diff --git a/testing_example/tests/src/Kernel/ExampleKernelNodeTest.php b/testing_example/tests/src/Kernel/ExampleKernelNodeTest.php
new file mode 100644
index 0000000..0830038
--- /dev/null
+++ b/testing_example/tests/src/Kernel/ExampleKernelNodeTest.php
@@ -0,0 +1,97 @@
+<?php
+
+namespace Drupal\Tests\testing_example\Kernel;
+
+use Drupal\KernelTests\KernelTestBase;
+use Drupal\simpletest\NodeCreationTrait;
+use Drupal\simpletest\UserCreationTrait;
+
+/**
+ * Demonstrate a kernel test.
+ *
+ * Kernel tests are used where APIs will be invoked, but the results of an HTTP
+ * request do not need to be examined.
+ *
+ * @group testing_example
+ * @group examples
+ */
+class ExampleKernelNodeTest extends KernelTestBase {
+
+  // Additional traits can be imported for more prebuilt tools in the tests.
+  use NodeCreationTrait;
+  use UserCreationTrait;
+
+  /**
+   * {@inheritdoc}
+   *
+   * Any modules added here will be loaded, along with anything in $modules in
+   * parent classes.
+   *
+   * These modules are not installed, but their services and hooks are
+   * available.
+   *
+   * @var string[]
+   */
+  public static $modules = ['user', 'system', 'field', 'node', 'text', 'filter'];
+
+  /**
+   * @var  \Drupal\user\Entity\User $owner
+   */
+  protected $owner;
+
+  /**
+   * {@inheritdoc}
+   *
+   * Use setUp() to do anything that is common to all the tests in this class.
+   *
+   * Group tests in a class so they can take advantage of setUp() activities
+   * as much as possible.
+   *
+   * In a Kernel test, setUp() can be responsible for creating any schema or
+   * database configuration which must exist for the test.
+   */
+  protected function setUp() {
+    parent::setUp();
+
+    // Figuring out what schema and EntitySchema and config to install is not
+    // easy. Use core kernel tests for examples. The baseline is that you have
+    // to manually install everything in the database that is needed. Sequences
+    // table is prerequisite of the 'node' schema.
+    $this->installSchema('system', ['sequences']);
+
+    // Install *module* schema for node/user modules.
+    $this->installSchema('node', ['node_access']);
+    $this->installSchema('user', ['users_data']);
+
+    // Install *entity* schema for the node entity.
+    $this->installEntitySchema('node');
+    $this->installEntitySchema('user');
+
+    // Install any config provided by the enabled.
+    $this->installConfig(['field', 'node', 'text', 'filter', 'user']);
+
+    $this->owner = $this->createUser([], 'testuser');
+  }
+
+  /**
+   * Create a user account using createUser() from the UserCreation trait.
+   */
+  public function testNodeCreation() {
+
+    // Unless there's a specific reason to do so, strings in tests do *not* need
+    // to be translatable with t().
+    $nodeTitle = 'Test Node!';
+
+    /** @var \Drupal\node\NodeInterface $node */
+    $node = $this->createNode([
+      'title' => $nodeTitle,
+      'type' => 'page',
+      'uid' => $this->owner->id(),
+    ]);
+
+    self::assertEquals($nodeTitle, $node->getTitle());
+
+    // Test a few more things about your node here.
+  }
+
+}
diff --git a/testing_example/tests/src/Kernel/ExampleKernelUserTest.php b/testing_example/tests/src/Kernel/ExampleKernelUserTest.php
new file mode 100644
index 0000000..b21145b
--- /dev/null
+++ b/testing_example/tests/src/Kernel/ExampleKernelUserTest.php
@@ -0,0 +1,86 @@
+<?php
+
+namespace Drupal\Tests\testing_example\Kernel;
+
+use Drupal\KernelTests\KernelTestBase;
+use Drupal\simpletest\UserCreationTrait;
+
+/**
+ * Demonstrate a kernel test.
+ *
+ * Kernel tests are used where APIs will be invoked, but the results of an HTTP
+ * request do not need to be examined.
+ *
+ * @group testing_example
+ * @group examples
+ */
+class ExampleKernelUserTest extends KernelTestBase {
+
+  // Additional traits can be imported for more prebuilt tools in the tests.
+  use UserCreationTrait;
+
+  /**
+   * {@inheritdoc}
+   *
+   * Any modules added here will be loaded, along with anything in $modules in
+   * parent classes.
+   *
+   * These modules are not installed, but their services and hooks are
+   * available.
+   *
+   * @var string[]
+   */
+  public static $modules = ['system', 'user'];
+
+  /**
+   * @var \Drupal\user\Entity\User $authUser
+   */
+  protected $authUser;
+
+  /**
+   * {@inheritdoc}
+   *
+   * Use setUp() to do anything that is common to all the tests in this class.
+   *
+   * Group tests in a class so they can take advantage of setUp() activities
+   * as much as possible.
+   *
+   * In a Kernel test, setUp() can be responsible for creating any schema or
+   * database configuration which must exist for the test.
+   */
+  protected function setUp() {
+    parent::setUp();
+
+    // Figuring out what schema and EntitySchema and config to install is not
+    // easy. Use core kernel tests for examples. The baseline is that you have
+    // to manually install everything in the database that is needed. Sequences
+    // table is prerequisite of the 'user' schema.
+    $this->installSchema('system', ['sequences']);
+
+    // Install *module* schema for user module.
+    $this->installSchema('user', ['users_data']);
+
+    // Install *entity* schema for the user entity.
+    $this->installEntitySchema('user');
+
+    // Install any config provided by the user module.
+    $this->installConfig(['user']);
+
+    $this->authUser = $this->createUser([], 'testuser');
+  }
+
+  /**
+   * Create a user account using createUser() from the UserCreation trait.
+   */
+  public function testUserCreation() {
+
+    // Create a user named 'extrauser'.
+    $account = $this->createUser([], 'extrauser');
+    // Assert that this user exists.
+    $this->assertEquals('extrauser', $account->getAccountName());
+
+    // Assert that our auth user is not the same user as extrauser.
+    $this->assertNotEquals($this->authUser->getAccountName(), $account->getAccountName());
+  }
+
+}
