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..88ff5b4
--- /dev/null
+++ b/phpunit_example/lib/Drupal/phpunit_example/AddClass.php
@@ -0,0 +1,38 @@
+<?php
+
+/**
+ * @file
+ * Contains Drupal\phpunit_example\AddClass
+ */
+
+namespace Drupal\phpunit_example;
+
+/**
+ * A class with features to show how to do unit testing.
+ */
+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
+   */
+  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..1317b4f
--- /dev/null
+++ b/phpunit_example/lib/Drupal/phpunit_example/Controller/PHPUnitExampleController.php
@@ -0,0 +1,46 @@
+<?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>Tests belong in their own <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>. Modules which are only used for testing purposes should be in <code>[your_module]/tests/modules/[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 SimpleTest 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>'),
+    );
+
+    return $build;
+  }
+
+}
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..36d36e0
--- /dev/null
+++ b/phpunit_example/lib/Drupal/phpunit_example/ProtectedPrivates.php
@@ -0,0 +1,40 @@
+<?php
+
+/**
+ * @file
+ * Contains Drupal\phpunit_example\AddClass
+ */
+
+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.
+ */
+class ProtectedPrivates {
+
+  /**
+   * Add two numbers.
+   */
+  protected function protectedAdd($a, $b) {
+    $adder = new AddClass();
+    return $adder->add($a, $b);
+  }
+
+  /**
+   * Add two numbers.
+   */
+  private function privateAdd($a, $b) {
+    $adder = new AddClass();
+    return $adder->add($a, $b);
+  }
+
+}
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..816d820
--- /dev/null
+++ b/phpunit_example/phpunit_example.module
@@ -0,0 +1,88 @@
+<?php
+/**
+ * @file
+ * Module file for phpunit_example_module.
+ */
+
+/**
+ * @defgroup phpunit_example Example: PHPUnit
+ * @ingroup examples
+ * @{
+ * This example demonstrates how a module can display a page at a given URL.
+ *
+ * It's important to understand how the menu system works in order to
+ * implement your own pages. See the Menu Example module for some insight.
+ *
+ * @see menu_example
+ */
+
+/**
+ * Implements hook_help().
+ *
+ * Through hook_help(), a module can make documentation available to the user
+ * for the module as a whole or for specific paths. Where the help appears
+ * depends on the $path specified.
+ *
+ * In the first example below, the help text will appear on the simple page
+ * defined in hook_menu below in the region designated for help text.
+ *
+ * In the second example, the text will be available through the module page as
+ * a link beside the module or on the admin help page (admin/help) in the list
+ * of help topics using the name of the module. To specify help in the admin
+ * section use the module name in the path as in the second case below.
+ *
+ * @see hook_help()
+ */
+function phpunit_example_help($path, $arg) {
+  switch ($path) {
+    case 'examples/page_example/simple':
+      // Help text for the simple page registered for this path.
+      return t('This is help text for the simple page.');
+
+    case 'admin/help#page_example':
+      // Help text for the admin section, using the module name in the path.
+      return t("This is help text created in the page example's second case.");
+  }
+}
+
+/**
+ * Implements hook_permission().
+ *
+ * Since the access to our new custom pages will be granted based on
+ * special permissions, we need to define what those permissions are here.
+ * This ensures that they are available to enable on the user role
+ * administration pages.
+ */
+function page_example_permission() {
+  return array(
+    'access simple page' => array(
+      'title' => t('Access simple page'),
+      'description' => t('Allow users to access simple page'),
+    ),
+    'access arguments page' => array(
+      'title' => t('Access page with arguments'),
+      'description' => t('Allow users to access page with arguments'),
+    ),
+  );
+}
+
+/**
+ * Implements hook_menu().
+ *
+ * We will define some menu items, and their paths will be interpreted as follows:
+ *
+ * @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..fdcca2a
--- /dev/null
+++ b/phpunit_example/phpunit_example.routing.yml
@@ -0,0 +1,7 @@
+# In order to create pages is necessary to define routes for them.
+phpunit_example_description:
+  pattern: 'examples/page_example'
+  defaults:
+    _content: '\Drupal\phpunit_example\Controller\PHPUnitExampleController::description'
+  requirements:
+    _access: 'TRUE'
diff --git a/phpunit_example/tests/Drupal/phpunit_example/Tests/AddClassTest.php b/phpunit_example/tests/Drupal/phpunit_example/Tests/AddClassTest.php
new file mode 100644
index 0000000..c0e011d
--- /dev/null
+++ b/phpunit_example/tests/Drupal/phpunit_example/Tests/AddClassTest.php
@@ -0,0 +1,166 @@
+<?php
+
+/**
+ * @file
+ * Contains Drupal\phpunit_example\Tests\AddClassTest
+ */
+
+namespace Drupal\phpunit_example\Tests;
+
+use Drupal\Tests\UnitTestCase;
+
+use Drupal\phpunit_example\AddClass;
+
+/**
+ * A Drupal PHPUnit test case against an example class.
+ *
+ * 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 if our tests
+ * passed by accident.
+ *
+ * So with that in mind, UnitTestCase provides us with very few methods.
+ * It's up to us to build out whatever dependencies we need.
+ *
+ * Annotation for api.drupal.org:
+ * @ingroup phpunit_example
+ *
+ * Annotation for PHPUnit:
+ * @group phpunit_example
+ */
+class AddClassTest extends UnitTestCase {
+
+  public static function getInfo() {
+    return array(
+      'name' => 'AddClass Unit Test',
+      'description' => 'Show some simple unit tests',
+      'group' => 'Examples',
+    );
+  }
+
+
+  /**
+   * Test 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);
+  }
+
+  /**
+   * 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(2, 3, 5),
+      array(20, 30, 50),
+    );
+  }
+
+  /**
+   * 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.
+   *
+   * 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($a, $b, $expected) {
+    $sut = new AddClass();
+    $this->assertEquals($sut->add($a, $b), $expected);
+  }
+
+  /**
+   * 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;
+  }
+
+  /**
+   * 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.
+   *
+   * @dataProvider addBadDataProvider
+   * @expectedException \InvalidArgumentException
+   *
+   * @see AddClassTest::addBadDataProvider()
+   */
+  public function testAddWithBadDataProvider($a, $b) {
+    $sut = new AddClass();
+    $sut->add($a, $b);
+  }
+
+}
diff --git a/phpunit_example/tests/Drupal/phpunit_example/Tests/ProtectedPrivatesTest.php b/phpunit_example/tests/Drupal/phpunit_example/Tests/ProtectedPrivatesTest.php
new file mode 100644
index 0000000..a5f449b
--- /dev/null
+++ b/phpunit_example/tests/Drupal/phpunit_example/Tests/ProtectedPrivatesTest.php
@@ -0,0 +1,154 @@
+<?php
+
+/**
+ * @file
+ * Contains Drupal\phpunit_example\Tests\AddClassTest
+ */
+
+namespace Drupal\phpunit_example\Tests;
+
+// @todo: Remove this once we resolve https://drupal.org/node/2025883
+require_once('Stubs/ProtectedPrivatesStub.php');
+
+use Drupal\Tests\UnitTestCase;
+
+use Drupal\phpunit_example\ProtectedPrivates;
+
+use Drupal\phpunit_example\Tests\Stubs\ProtectedPrivatesStub;
+
+/**
+ * A Drupal PHPUnit test case against an example class.
+ *
+ * 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 if our tests
+ * passed by accident.
+ *
+ * So with that in mind, UnitTestCase provides us with very few methods.
+ * It's up to us to build out whatever dependencies we need.
+ *
+ * Annotation for api.drupal.org:
+ * @ingroup phpunit_example
+ *
+ * Annotation for PHPUnit:
+ * @group phpunit_example
+ */
+class 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 ( 2, 3, 5),
+    );
+  }
+
+  /**
+   * 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($a, $b, $expected) {
+    // 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($sum, $expected);
+  }
+
+  /**
+   * 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.
+    $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($a, $b, $expected) {
+    $stub = new ProtectedPrivatesStub();
+    $this->assertEquals($stub->stub_protectedAdd($a, $b), $expected);
+  }
+
+  /**
+   * 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 ProtectedPrivatesStub();
+    $stub->stub_protectedAdd($a, $b);
+  }
+
+}
diff --git a/phpunit_example/tests/Drupal/phpunit_example/Tests/Stubs/ProtectedPrivatesStub.php b/phpunit_example/tests/Drupal/phpunit_example/Tests/Stubs/ProtectedPrivatesStub.php
new file mode 100644
index 0000000..f795b95
--- /dev/null
+++ b/phpunit_example/tests/Drupal/phpunit_example/Tests/Stubs/ProtectedPrivatesStub.php
@@ -0,0 +1,33 @@
+<?php
+
+/**
+ * @file
+ * Contains Drupal\phpunit_example\Tests\ProtectedPrivatesStub
+ */
+
+namespace Drupal\phpunit_example\Tests\Stubs;
+
+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 on it.
+ *
+ * This stub class allows us to get access to the protected method.
+ */
+class ProtectedPrivatesStub extends ProtectedPrivates {
+
+  /**
+   * A stub class so we can access a protected method.
+   *
+   * We use a naming convention so our test code is clear that
+   * we are using a stub method.
+   */
+  public function stub_protectedAdd($a, $b) {
+    return $this->protectedAdd($a, $b);
+  }
+
+}
