diff --git a/phpunit_example/lib/Drupal/phpunit_example/AddClass.php b/phpunit_example/lib/Drupal/phpunit_example/AddClass.php
new file mode 100644
index 0000000..44e9631
--- /dev/null
+++ b/phpunit_example/lib/Drupal/phpunit_example/AddClass.php
@@ -0,0 +1,41 @@
+<?php
+
+/**
+ * @file
+ * Contains Drupal\phpunit_example\AddClass
+ */
+
+namespace Drupal\phpunit_example;
+
+/**
+ * A class with features to show how to do unit testing.
+ *
+ * @ingroup phpunit_example
+ */
+class AddClass {
+
+  /**
+   * A simple addition method with validity checking.
+   *
+   * @param $a
+   *   A number to add.
+   * @param $b
+   *   Another number to add.
+   *
+   * @return
+   *   The sum of $a and $b.
+   *
+   * @throws \InvalidArgumentException
+   *   If either $a or $b is non-numeric, we can't add, so we throw.
+   */
+  public function add($a, $b) {
+    // Check whether the arguments are numeric.
+    foreach(array($a, $b) as $argument) {
+      if (!is_numeric($argument)) {
+        throw new \InvalidArgumentException('Arguments must be numeric.');
+      }
+    }
+    return $a + $b;
+  }
+
+}
diff --git a/phpunit_example/lib/Drupal/phpunit_example/Controller/PHPUnitExampleController.php b/phpunit_example/lib/Drupal/phpunit_example/Controller/PHPUnitExampleController.php
new file mode 100644
index 0000000..25a99f1
--- /dev/null
+++ b/phpunit_example/lib/Drupal/phpunit_example/Controller/PHPUnitExampleController.php
@@ -0,0 +1,52 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\phpunit_example\Controller\PHPUnitExampleController.
+ */
+
+namespace Drupal\phpunit_example\Controller;
+
+/**
+ * Controller routines for filter routes.
+ */
+class PHPUnitExampleController {
+
+  /**
+   * Displays a page with a descriptive page.
+   *
+   * Our router maps this method to the path 'examples/phpunit_example'.
+   */
+  function description() {
+    $build = array(
+      '#markup' => t('<h2>PHPUnit for Drupal: A very basic how-to.</h2>
+
+<h3>How to use this example module</h3>
+
+<p>You really should be reading the various docblocks in the test files.</p>
+
+<h3>Drupalisms</h3>
+
+<ul>
+<li><p>PHPUnit tests belong in their own directory, so they won&#39;t be loaded by the autoloader during normal bootstrap. This means you should have a <code>/tests</code> directory in the root of your module directory.</p></li>
+<li><p>Your tests should be in the <code>Drupal\[your_module]\Tests</code> namespace. Under Drupal&#39;s PSR-0 system, this means your PHPUnit-based tests should go in <code>[your_module]/tests/Drupal/[your_module]/Tests/</code>.</p></li>
+<li><p>Modules which are only used for testing purposes by PHPUnit should be in <code>[your_module]/tests/Drupal/[your_module]/Tests/[testing_module]/</code></p></li>
+<li><p>Your test case should subclass <code>Drupal\Tests\UnitTestCase</code>.</p></li>
+<li><p>You can run PHPUnit-based tests from within Drupal 8 by enabling the Testing module and then selecting the PHPUnit group from the testing page. As of this writing, this method doesn&#39;t provide any useful output.</p></li>
+</ul>
+
+<h3>Standard PHPUnit Practices</h3>
+
+<p>You can (and really, should) run PHPUnit from the command line. On unix-based systems this means you need to <code>cd core</code> and then <code>./vendor/bin/phpunit</code>.</p>
+
+<p>Also, you should mark your tests as belonging to a group, so they can be run independently. You do this by annotating your test classes with <code>@group GroupName</code>. Currently, no conventions exist for how these groups should be named. You use groups like this: <code>./vendor/bin/phpunit --group GroupName</code>.</p>
+
+<p>So, for instance, to run all of the PHPUnit example tests, you would type <code>./vendor/bin/phpunit --group phpunit_example</code>.</p>
+
+<p>As you can see, including a <code>@group</code> annotation is a good idea.</p>'),
+    );
+
+    return $build;
+  }
+
+}
diff --git a/phpunit_example/lib/Drupal/phpunit_example/DisplayInfoInterface.php b/phpunit_example/lib/Drupal/phpunit_example/DisplayInfoInterface.php
new file mode 100644
index 0000000..6200254
--- /dev/null
+++ b/phpunit_example/lib/Drupal/phpunit_example/DisplayInfoInterface.php
@@ -0,0 +1,38 @@
+<?php
+
+/**
+ * @file
+ * Contains Drupal\phpunit_example\DisplayInfoInterface
+ */
+
+namespace Drupal\phpunit_example;
+
+/**
+ * An interface to objects that provide displayable information.
+ *
+ * Part of the PHPUnit Example module.
+ *
+ * Think of this interface as representing objects that can return some sort of
+ * display information, such as getInfo() in Drupal tests, or an .info.yml file.
+ *
+ * @ingroup phpunit_example
+ */
+interface DisplayInfoInterface {
+
+  /**
+   * Get displayable name.
+   *
+   * @returns string
+   *    The display name for the item this object represents.
+   */
+  public function getDisplayName();
+
+  /**
+   * Get displayable description.
+   *
+   * @returns string
+   *    The displayable description for the item this object represents.
+   */
+  public function getDisplayDescription();
+
+}
diff --git a/phpunit_example/lib/Drupal/phpunit_example/DisplayManager.php b/phpunit_example/lib/Drupal/phpunit_example/DisplayManager.php
new file mode 100644
index 0000000..ef51e91
--- /dev/null
+++ b/phpunit_example/lib/Drupal/phpunit_example/DisplayManager.php
@@ -0,0 +1,48 @@
+<?php
+
+/**
+ * @file
+ * Contains Drupal\phpunit_example\DisplayManager
+ */
+
+namespace Drupal\phpunit_example;
+
+use Drupal\phpunit_example\DisplayInfoInterface;
+
+/**
+ * An example class to demonstrate unit testing.
+ *
+ * Think of this class as a class that collects DisplayInfoInterface
+ * objects, because that's what it is. It also might go on to one day
+ * display lists of info about these info objects.
+ *
+ * But it never will, because it's just an example class.
+ *
+ * Part of the PHPUnit Example module.
+ *
+ * @ingroup phpunit_example
+ */
+class DisplayManager {
+
+  protected $items;
+
+  public function addDisplayableItem(DisplayInfoInterface $item) {
+    $this->items[$item->getDisplayName()] = $item;
+  }
+
+  public function countDisplayableItems() {
+    return count($this->items);
+  }
+
+  public function displayableItems() {
+    return $this->items;
+  }
+
+  public function item($name) {
+    if (isset($this->items[$name])) {
+      return $this->items[$name];
+    }
+    return NULL;
+  }
+
+}
diff --git a/phpunit_example/lib/Drupal/phpunit_example/ProtectedPrivates.php b/phpunit_example/lib/Drupal/phpunit_example/ProtectedPrivates.php
new file mode 100644
index 0000000..74e0d73
--- /dev/null
+++ b/phpunit_example/lib/Drupal/phpunit_example/ProtectedPrivates.php
@@ -0,0 +1,64 @@
+<?php
+
+/**
+ * @file
+ * Contains Drupal\phpunit_example\ProtectedPrivates
+ */
+
+namespace Drupal\phpunit_example;
+
+use Drupal\phpunit_example\AddClass;
+
+/**
+ * A class with features to show how to do unit testing.
+ *
+ * This class has private and protected methods to demonstrate
+ * how to test with reflection.
+ *
+ * protectedAdd() and privateAdd() are shim methods to AddClass::add().
+ * We do this so we're concentrating on the testing instead of the
+ * code being tested.
+ *
+ * @ingroup phpunit_example
+ */
+class ProtectedPrivates {
+
+  /**
+   * A simple addition method with validity checking.
+   *
+   * @param $a
+   *   A number to add.
+   * @param $b
+   *   Another number to add.
+   *
+   * @return
+   *   The sum of $a and $b.
+   *
+   * @throws \InvalidArgumentException
+   *   If either $a or $b is non-numeric, we can't add, so we throw.
+   */
+  protected function protectedAdd($a, $b) {
+    $adder = new AddClass();
+    return $adder->add($a, $b);
+  }
+
+  /**
+   * A simple addition method with validity checking.
+   *
+   * @param $a
+   *   A number to add.
+   * @param $b
+   *   Another number to add.
+   *
+   * @return
+   *   The sum of $a and $b.
+   *
+   * @throws \InvalidArgumentException
+   *   If either $a or $b is non-numeric, we can't add, so we throw.
+   */
+  private function privateAdd($a, $b) {
+    $adder = new AddClass();
+    return $adder->add($a, $b);
+  }
+
+}
diff --git a/phpunit_example/lib/Drupal/phpunit_example/Tests/PHPUnitExampleSimpleTest.php b/phpunit_example/lib/Drupal/phpunit_example/Tests/PHPUnitExampleSimpleTest.php
new file mode 100644
index 0000000..8779f49
--- /dev/null
+++ b/phpunit_example/lib/Drupal/phpunit_example/Tests/PHPUnitExampleSimpleTest.php
@@ -0,0 +1,40 @@
+<?php
+/**
+ * @file
+ * SimpleTests for phpunit_example module.
+ */
+
+namespace Drupal\phpunit_example\Tests;
+use Drupal\simpletest\WebTestBase;
+
+/**
+ * Default test case for the phpunit_example module.
+ *
+ * Note that this is _not_ a PHPUnit-based test.
+ *
+ * @ingroup phpunit_example
+ */
+class PHPUnitExampleSimpleTest extends WebTestBase {
+
+  public static $modules = array('phpunit_example');
+
+  public static function getInfo() {
+    return array(
+      'name' => 'SimpleTest for PHPUnit Example module',
+      'description' => 'Functional tests for the PHPUnit Example module',
+      'group' => 'Examples',
+    );
+  }
+
+  /**
+   * Very simple regression test for PHPUnit Example module.
+   *
+   * All we do is enable PHPUnit Example and see if it can successfully
+   * return its main page.
+   */
+  public function testController() {
+    $this->drupalGet('examples/phpunit_example');
+    $this->assertResponse(200, 'The PHPUnit Example description page is available.');
+  }
+
+}
diff --git a/phpunit_example/phpunit_example.info.yml b/phpunit_example/phpunit_example.info.yml
new file mode 100644
index 0000000..c6d179c
--- /dev/null
+++ b/phpunit_example/phpunit_example.info.yml
@@ -0,0 +1,5 @@
+name: PHPUnit example
+type: module
+description: 'How to use PHPUnit-based tests with Drupal 8.'
+package: Example modules
+core: 8.x
diff --git a/phpunit_example/phpunit_example.module b/phpunit_example/phpunit_example.module
new file mode 100644
index 0000000..0c01000
--- /dev/null
+++ b/phpunit_example/phpunit_example.module
@@ -0,0 +1,47 @@
+<?php
+/**
+ * @file
+ * Module file for phpunit_example.
+ */
+
+/**
+ * @defgroup phpunit_example Example: PHPUnit
+ * @ingroup examples
+ * @{
+ * This example demonstrates PHPUnit for Drupal 8 unit testing.
+ */
+
+/**
+ * Implements hook_help().
+ *
+ * @see hook_help()
+ */
+function phpunit_example_help($path, $arg) {
+  switch ($path) {
+    case 'examples/phpunit_example':
+      // Help text for the simple page registered for this path.
+      return t('This is the help text for PHPUnit example.');
+  }
+}
+
+/**
+ * Implements hook_menu().
+ *
+ * We will define a single menu route, so that we can give the user some
+ * helpful introductory information.
+ *
+ * @see hook_menu()
+ * @see menu_example
+ */
+function phpunit_example_menu() {
+  $items['examples/phpunit_example'] = array(
+    'title' => 'PHPUnit Example',
+    'route_name' => 'phpunit_example_description',
+    'expanded' => TRUE,
+  );
+  return $items;
+}
+
+/**
+ * @} End of "defgroup phpunit_example".
+ */
diff --git a/phpunit_example/phpunit_example.routing.yml b/phpunit_example/phpunit_example.routing.yml
new file mode 100644
index 0000000..f0b8160
--- /dev/null
+++ b/phpunit_example/phpunit_example.routing.yml
@@ -0,0 +1,8 @@
+# phpunit_example only has one route. It is to a page explaining
+# the module.
+phpunit_example_description:
+  pattern: 'examples/phpunit_example'
+  defaults:
+    _content: '\Drupal\phpunit_example\Controller\PHPUnitExampleController::description'
+  requirements:
+    _access: 'TRUE'
diff --git a/phpunit_example/tests/Drupal/phpunit_example/Tests/Double_DisplayManagerTest.php b/phpunit_example/tests/Drupal/phpunit_example/Tests/Double_DisplayManagerTest.php
new file mode 100644
index 0000000..5c5c810
--- /dev/null
+++ b/phpunit_example/tests/Drupal/phpunit_example/Tests/Double_DisplayManagerTest.php
@@ -0,0 +1,62 @@
+<?php
+
+/**
+ * @file
+ * Contains Drupal\phpunit_example\Tests\Double_DisplayManagerTest
+ */
+
+namespace Drupal\phpunit_example\Tests;
+
+use Drupal\Tests\UnitTestCase;
+
+use Drupal\phpunit_example\DisplayManager;
+use Drupal\phpunit_example\DisplayInfoInterface;
+
+/**
+ * A PHPUnit example test case against an example class.
+ *
+ * @todo: More documentation.
+ *
+ * @ingroup phpunit_example
+ * @group phpunit_example
+ */
+class Double_DisplayManagerTest extends UnitTestCase {
+
+  public static function getInfo() {
+    return array(
+      'name' => 'DisplayManager Unit Test',
+      'description' => 'Demonstrate unit testing with test doubles.',
+      'group' => 'Examples',
+    );
+  }
+
+  public function testSimpleMockDisplayManager() {
+    // Setting up:
+    // Get a mock object belonging to our desired interface.
+    // Note that we have to fully qualify the domain name
+    // for PHPUnit's benefit.
+    $mock = $this->getMock('Drupal\phpunit_example\DisplayInfoInterface');
+    // Here we're illustrating that the mock object belongs to
+    // our interface.
+    $this->assertTrue($mock instanceof DisplayInfoInterface);
+    // 'Program' our mock object to return a value for getDisplayName().
+    // expects($this->any()) tells the mock to return this value any time
+    // the method is called.
+    $mock->expects($this->any())
+         ->method('getDisplayName')
+         ->will($this->returnValue('the display name'));
+
+    // Create a DisplayManager, the class we're actually testing here.
+    $dm = new DisplayManager();
+    // Give it the mocked info object.
+    $dm->addDisplayableItem($mock);
+    // Assert that our DisplayManager has exactly one display object (our mock).
+    $this->assertEquals(1, $dm->countDisplayableItems());
+    // Assert that the DisplayManager can find our mocked info object.
+    $this->assertSame($mock, $dm->item('the display name'));
+    // Assert that the DisplayManager can't find an info object
+    // that it shouldn't have.
+    $this->assertNull($dm->item('nonexistant'));
+  }
+
+}
diff --git a/phpunit_example/tests/Drupal/phpunit_example/Tests/ProviderException_AddClassTest.php b/phpunit_example/tests/Drupal/phpunit_example/Tests/ProviderException_AddClassTest.php
new file mode 100644
index 0000000..a2969e2
--- /dev/null
+++ b/phpunit_example/tests/Drupal/phpunit_example/Tests/ProviderException_AddClassTest.php
@@ -0,0 +1,185 @@
+<?php
+
+/**
+ * @file
+ * Contains Drupal\phpunit_example\Tests\ProviderException_AddClassTest
+ */
+
+namespace Drupal\phpunit_example\Tests;
+
+use Drupal\Tests\UnitTestCase;
+
+use Drupal\phpunit_example\AddClass;
+
+/**
+ * A PHPUnit example test case against an example class.
+ *
+ * This test case demonstrates the following PHPUnit annotations:
+ * - dataProvider
+ * - expectedException
+ *
+ * PHPUnit looks for classes with names ending in 'Test'. Then it
+ * looks to see whether that class is a subclass of
+ * \PHPUnit_Framework_TestCase. Drupal supplies us with
+ * Drupal\Tests\UnitTestCase, which is a subclass of
+ * \PHPUnit_Framework_TestCase. So yay, PHPUnit will find this class.
+ *
+ * In unit testing, there should be as few dependencies as possible.
+ * We want the smallest number of moving parts to be interacting in
+ * our test, or we won't be sure where the errors are, or whether our
+ * tests passed by accident.
+ *
+ * So with that in mind, it's up to us to build out whatever
+ * dependencies we need. In the case of AddClass, our needs are meager;
+ * we only want an instance of AddClass so we can test its add() method.
+ *
+ * @ingroup phpunit_example
+ * @group phpunit_example
+ */
+class ProviderException_AddClassTest extends UnitTestCase {
+
+  public static function getInfo() {
+    return array(
+      'name' => 'AddClass Unit Test',
+      'description' => 'Show some simple unit tests',
+      'group' => 'Examples',
+    );
+  }
+
+  /**
+   * Very simple test of AddClass::add().
+   *
+   * This is a very simple unit test of a single method. It has
+   * a single assertion, and that assertion is probably going to
+   * pass. It ignores most of the problems that could arise in the
+   * method under test, so therefore: It is not a very good test.
+   */
+  public function testAdd() {
+    $sut = new AddClass();
+    $this->assertEquals($sut->add(2, 3), 5);
+  }
+
+  /**
+   * Test AddClass::add() with a data provider method.
+   *
+   * This method is very similar to testAdd(), but uses a data provider method
+   * to test with a wider range of data.
+   *
+   * You can tell PHPUnit which method is the data provider using the
+   * '@dataProvider' annotation.
+   *
+   * The data provider method just returns a big array of arrays of arguments.
+   * That is, for each time you want this test method run, the data provider
+   * should create an array of arguments for this method. In this case, it's
+   * $expected, $a, and $b. So one set of arguments would look a bit like this
+   * pseudocode:
+   *
+   * @code
+   * array( valueForExpected, valueForA, valueForB )
+   * @endcode
+   *
+   * It would then wrap this up in a higher-level array, so that PHPUnit can
+   * loop through them, like this pseudocode:
+   *
+   * @code
+   * return array( array(first, set), array (next, set) );
+   * @endcode
+   *
+   * This test has a better methodology than testAdd(), because it can easily
+   * be adapted by other developers, and because it tries more than one data
+   * set. This test is much better than testAdd(), although it still only
+   * tests 'good' data. When combined with testAddWithBadDataProvider(),
+   * we get a better picture of the behavior of the method under test.
+   *
+   * @dataProvider addDataProvider
+   *
+   * @see AddClassTest::addDataProvider()
+   */
+  public function testAddWithDataProvider($expected, $a, $b) {
+    $sut = new AddClass();
+    $this->assertEquals($expected, $sut->add($a, $b));
+  }
+
+  /**
+   * Test AddClass::add() with data that should throw an exception.
+   *
+   * This method is similar to testAddWithDataProvider(), but the data
+   * provider gives us data that should throw an exception.
+   *
+   * This test uses the '@expectedException' annotation to tell PHPUnit that
+   * a thrown exception should pass the test. You specify a
+   * fully-qualified exception class name. If you specify \Exception, PHPUnit
+   * will pass any exception, whereas a more specific subclass of \Exception
+   * will require that exception type to be thrown.
+   *
+   * Alternately, you can use try and catch blocks with assertions in order
+   * to test exceptions. We won't demonstrate that here; it's a much better
+   * idea to test your exceptions with @expectedException.
+   *
+   * @dataProvider addBadDataProvider
+   * @expectedException \InvalidArgumentException
+   *
+   * @see AddClassTest::addBadDataProvider()
+   */
+  public function testAddWithBadDataProvider($a, $b) {
+    $sut = new AddClass();
+    $sut->add($a, $b);
+  }
+
+  /**
+   * Data provider for testAddWithDataProvider().
+   *
+   * Data provider methods take no arguments and return an array of data
+   * to use for tests. Each element of the array is another array, which
+   * corresponds to the arguments in the test method's signature.
+   *
+   * Note also that PHPUnit tries to run tests using methods that begin
+   * with 'test'. This means that data provider method names should not
+   * begin with 'test'. Also, by convention, they should end with
+   * 'DataProvider'.
+   *
+   * @see AddClassTest::testAddWithDataProvider()
+   */
+  public function addDataProvider() {
+    return array(
+      // array($a, $b, $expected)
+      array(5, 2, 3),
+      array(50, 20, 30),
+    );
+  }
+
+  /**
+   * Data provider for testAddWithBadDataProvider().
+   *
+   * Since AddClass::add() can throw exceptions, it's time
+   * to give it some data that will cause these exceptions.
+   *
+   * add() should throw exceptions if either of it's arguments are
+   * not numeric, and we will generate some test data to prove that
+   * this is what it actually does.
+   *
+   * @see AddClassTest::testAddWithBadDataProvider()
+   */
+  public function addBadDataProvider() {
+    $badData = array();
+    // Set up an array with data that should cause add()
+    // to throw an exception.
+    $badDataTypes = array('string', FALSE, array('foo'), new \stdClass());
+    // Create some data where both $a and $b are bad types.
+    foreach ($badDataTypes as $badDatumA) {
+      foreach ($badDataTypes as $badDatumB) {
+        $badData[] = array($badDatumA, $badDatumB);
+      }
+    }
+    // Create some data where $a is good and $b is bad.
+    foreach($badDataTypes as $badDatumB) {
+      $badData[] = array(1, $badDatumB);
+    }
+    // Create some data where $b is good and $a is bad.
+    foreach($badDataTypes as $badDatumA) {
+      $badData[] = array($badDatumA, 1);
+    }
+    return $badData;
+  }
+
+}
diff --git a/phpunit_example/tests/Drupal/phpunit_example/Tests/Reflection_ProtectedPrivatesTest.php b/phpunit_example/tests/Drupal/phpunit_example/Tests/Reflection_ProtectedPrivatesTest.php
new file mode 100644
index 0000000..b29e9f5
--- /dev/null
+++ b/phpunit_example/tests/Drupal/phpunit_example/Tests/Reflection_ProtectedPrivatesTest.php
@@ -0,0 +1,158 @@
+<?php
+
+/**
+ * @file
+ * Contains Drupal\phpunit_example\Tests\Reflection_ProtectedPrivatesTest
+ */
+
+namespace Drupal\phpunit_example\Tests;
+
+use Drupal\Tests\UnitTestCase;
+
+use Drupal\phpunit_example\ProtectedPrivates;
+
+use Drupal\phpunit_example\Tests\Subclasses\ProtectedPrivatesSubclass;
+
+/**
+ * A PHPUnit example test case against an example class.
+ *
+ * This test case demonstrates the following unit testing patterns and topics:
+ * - Using reflection to test private class methods.
+ * - Using subclassing to test protected class methods.
+ *
+ * If you are reading this and don't understand the basics of unit testing,
+ * start reading AddClassTest instead.
+ *
+ * This test class uses reflection and subclassing to work around method
+ * access problems. Since, by design, a private method is inaccessible,
+ * we have to use reflection to gain access to the method for our own
+ * purposes.
+ *
+ * The getAccessibleMethod() method demonstrates a way to do this.
+ *
+ * Once we've set the method to be accessible, we can use it as if
+ * it were public.
+ *
+ * The same technique can be used for protected methods. However, there
+ * might be times when it makes more sense to subclass the class under
+ * test, and just make a public accessor method that way. So we
+ * demonstrate that here in testProtectedAdd().
+ *
+ * @ingroup phpunit_example
+ * @group phpunit_example
+ */
+class Reflection_ProtectedPrivatesTest extends UnitTestCase {
+
+  public static function getInfo() {
+    return array(
+      'name' => 'ProtectedPrivates Unit Test',
+      'description' => 'Demonstrate unit testing of restricted methods.',
+      'group' => 'Examples',
+    );
+  }
+
+  /**
+   * Get an accessible method using reflection.
+   */
+  public function getAccessibleMethod($className, $methodName) {
+    $class = new \ReflectionClass($className);
+    $method = $class->getMethod($methodName);
+    $method->setAccessible(true);
+    return $method;
+  }
+
+  /**
+   * Good data provider.
+   */
+  public function addDataProvider() {
+    return array (
+      array (5, 2, 3),
+    );
+  }
+
+  /**
+   * Test ProtectedPrivate::privateAdd().
+   *
+   * We want to test a private method on a class. This is problematic
+   * because, by design, we don't have access to this method. However,
+   * we do have a tool available to help us out with this problem:
+   * We can override the accessibility of a method using reflection.
+   *
+   * @dataProvider addDataProvider
+   */
+  public function testPrivateAdd($expected, $a, $b) {
+    // Get a reflected, accessible version of the privateAdd() method.
+    $privateMethod = $this->getAccessibleMethod(
+      'Drupal\phpunit_example\ProtectedPrivates',
+      'privateAdd'
+    );
+    // Create a new ProtectedPrivates object.
+    $pp = new ProtectedPrivates();
+    // Use the reflection to invoke on the object.
+    $sum = $privateMethod->invokeArgs($pp, array($a, $b));
+    // Make an assertion.
+    $this->assertEquals($expected, $sum);
+  }
+
+  /**
+   * Bad data provider.
+   */
+  public function addBadDataProvider() {
+    return array (
+      array ('string', array()),
+    );
+  }
+
+  /**
+   * Test ProtectedPrivate::privateAdd() with bad data.
+   *
+   * This is essentially the same test as testPrivateAdd(), but using
+   * non-numeric data. This lets us test the exception-throwing ability
+   * of this private method.
+   *
+   * @expectedException \InvalidArgumentException
+   * @dataProvider addBadDataProvider
+   */
+  public function testPrivateAddBadData($a, $b) {
+    // Get a reflected, accessible version of the privateAdd() method.
+    $privateMethod = $this->getAccessibleMethod(
+      'Drupal\phpunit_example\ProtectedPrivates',
+      'privateAdd');
+    // Create a new ProtectedPrivates object.
+    $pp = new ProtectedPrivates();
+    // Use the reflection to invoke on the object.
+    // This should throw an exception.
+    $sum = $privateMethod->invokeArgs($pp, array($a, $b));
+  }
+
+  /**
+   * Test ProtectedPrivates::protectedAdd() using a stub class.
+   *
+   * We could use the same reflection technique to test protected
+   * methods, just like we did with private ones.
+   *
+   * But sometimes it might make more sense to use a stub class
+   * which will have access to the protected method. That's what
+   * we'll demonstrate here.
+   *
+   * @dataProvider addDataProvider
+   */
+  public function testProtectedAdd($expected, $a, $b) {
+    $stub = new ProtectedPrivatesSubclass();
+    $this->assertEquals($expected, $stub->sub_protectedAdd($a, $b));
+  }
+
+  /**
+   * Test ProtectedPrivates::protectedAdd() with bad data using a stub class.
+   *
+   * This test is similar to testProtectedAdd(), but expects an exception.
+   *
+   * @expectedException \InvalidArgumentException
+   * @dataProvider addBadDataProvider
+   */
+  public function testProtectedAddBadData($a, $b) {
+    $stub = new ProtectedPrivatesSubclass();
+    $stub->sub_protectedAdd($a, $b);
+  }
+
+}
diff --git a/phpunit_example/tests/Drupal/phpunit_example/Tests/Subclasses/ProtectedPrivatesSubclass.php b/phpunit_example/tests/Drupal/phpunit_example/Tests/Subclasses/ProtectedPrivatesSubclass.php
new file mode 100644
index 0000000..c12f98b
--- /dev/null
+++ b/phpunit_example/tests/Drupal/phpunit_example/Tests/Subclasses/ProtectedPrivatesSubclass.php
@@ -0,0 +1,35 @@
+<?php
+
+/**
+ * @file
+ * Contains Drupal\phpunit_example\Tests\Stubs\ProtectedPrivatesSubclass
+ */
+
+namespace Drupal\phpunit_example\Tests\Subclasses;
+
+use Drupal\phpunit_example\ProtectedPrivates;
+
+/**
+ * A class for testing ProtectedPrivate::protectedAdd().
+ *
+ * We could use reflection to test protected methods, just as with
+ * private ones. But in some circumstances it might make more sense
+ * to make a subclass and then run the tests against it.
+ *
+ * This subclass allows us to get access to the protected method.
+ *
+ * @ingroup phpunit_example
+ */
+class ProtectedPrivatesSubclass extends ProtectedPrivates {
+
+  /**
+   * A stub class so we can access a protected method.
+   *
+   * We use a naming convention to make it clear that we are using a
+   * shimmed method.
+   */
+  public function sub_protectedAdd($a, $b) {
+    return $this->protectedAdd($a, $b);
+  }
+
+}
