diff --git a/composer.json b/composer.json
index fd1828a5b601eb66e0e6a71057d3760e7353de1d..deb456ffb4d957af355d5a74ed1bf0feef551420 100644
--- a/composer.json
+++ b/composer.json
@@ -32,6 +32,7 @@
         "composer-plugin-api": "^1.0.0",
         "dealerdirect/phpcodesniffer-composer-installer": "^0.4.3",
         "drupal-code-builder/drupal-code-builder-drush": "^9.0",
+        "drupal-composer/drupal-scaffold": "^2.3",
         "drupal/coder": "^8.2",
         "lakedrops/ahoy": "^1.0.0",
         "lakedrops/behat4drupal": "^1.0.0",
@@ -39,8 +40,10 @@
         "lakedrops/docker4drupal": "^1.0.0",
         "lakedrops/dorgflow": "^1.0.0",
         "mikey179/vfsStream": "^1.6",
+        "phpmd/phpmd": "^2.6.0",
         "phpspec/prophecy": "^1.8",
-        "phpunit/phpunit": "4 - 5",
+        "phpunit/phpunit": "^6.5",
+        "squizlabs/php_codesniffer": "^3.3",
         "symfony/css-selector": "^3.4",
         "symfony/debug": "^3.4",
         "symfony/phpunit-bridge": "^3.4"
diff --git a/src/Handler.php b/src/Handler.php
index 19c53f36eb1231baedca4f82f2c96ba1cd63520c..df5e59892a2fb2eae1bd9ed76a13cc073b9c2fad 100644
--- a/src/Handler.php
+++ b/src/Handler.php
@@ -105,12 +105,11 @@ class Handler {
     // Directory where this plugin is being installed.
     $pluginRoot = $installationManager->getInstallPath($this->getPackage('lakedrops/d8-project-scaffold-developer'));
 
-    // Create contrib/custom dirs for modules, profiles, themes and drush.
+    // Create contrib/custom dirs for modules, profiles and themes.
     foreach ([
       $webRoot . '/modules',
       $webRoot . '/profiles',
       $webRoot . '/themes',
-      'drush',
     ] as $dir) {
       foreach (['contrib', 'custom'] as $subdir) {
         $path = $dir . '/' . $subdir;
@@ -129,6 +128,8 @@ class Handler {
       'settings/default',
       'files/default/files',
       'files/default/private',
+      'drush',
+      'tests',
     ] as $dir) {
       $path = $projectRoot . '/' . $dir;
       if (!$fs->exists($path)) {
@@ -181,6 +182,11 @@ class Handler {
       $fs->copy($pluginRoot . '/templates/drush/' . $template, 'drush/' . $template);
     }
 
+    // Copy Test files.
+    foreach (['phpunit.xml.dist'] as $template) {
+      $fs->copy($pluginRoot . '/templates/tests/' . $template, 'tests/' . $template);
+    }
+
     // Link Drupal site's config directory.
     if (!$fs->exists($webRoot . '/sites/default/files/config')) {
       $rel = substr($fs->makePathRelative($projectRoot . '/config/default', $projectRoot . '/files/default/files/config'), 3, -1);
diff --git a/src/Plugin.php b/src/Plugin.php
index f27a91cee4c7d7a51bd2580612cf4f24ce2121d9..5d9b076f218ac21dc876643255b8b55122533c82 100644
--- a/src/Plugin.php
+++ b/src/Plugin.php
@@ -8,6 +8,7 @@ use Composer\IO\IOInterface;
 use Composer\Plugin\PluginInterface;
 use Composer\Script\Event;
 use Composer\Script\ScriptEvents;
+use DrupalComposer\DrupalScaffold\Handler as DrupalScaffoldHandler;
 
 /**
  * Composer plugin for handling drupal scaffold.
@@ -21,11 +22,19 @@ class Plugin implements PluginInterface, EventSubscriberInterface {
    */
   protected $handler;
 
+  /**
+   * The scaffold handler object for events.
+   *
+   * @var \DrupalComposer\DrupalScaffold\Handler
+   */
+  protected $scaffoldHandler;
+
   /**
    * {@inheritdoc}
    */
   public function activate(Composer $composer, IOInterface $io) {
     $this->handler = new Handler($composer, $io);
+    $this->scaffoldHandler = new DrupalScaffoldHandler($composer, $io);
   }
 
   /**
@@ -34,6 +43,7 @@ class Plugin implements PluginInterface, EventSubscriberInterface {
   public static function getSubscribedEvents() {
     return array(
       ScriptEvents::POST_CREATE_PROJECT_CMD => 'postCreateProject',
+      ScriptEvents::POST_UPDATE_CMD => 'postUpdate',
     );
   }
 
@@ -44,9 +54,20 @@ class Plugin implements PluginInterface, EventSubscriberInterface {
    *   The event that triggered the plugin.
    */
   public function postCreateProject(Event $event) {
+    $this->scaffoldHandler->downloadScaffold();
     $this->handler->setupLakeDropsProject($event);
   }
 
+  /**
+   * Post update event callback.
+   *
+   * @param \Composer\Script\Event $event
+   *   The event that triggered the plugin.
+   */
+  public function postUpdate(Event $event) {
+    $this->scaffoldHandler->downloadScaffold();
+  }
+
   /**
    * Callback to setup the project.
    *
diff --git a/src/TestSuite/Base.php b/src/TestSuite/Base.php
new file mode 100644
index 0000000000000000000000000000000000000000..87f41e4cf75d289594a8c420a9b6d9beb8b1d16d
--- /dev/null
+++ b/src/TestSuite/Base.php
@@ -0,0 +1,53 @@
+<?php
+
+namespace LakeDrops\Drupal8ScaffoldDeveloper\TestSuites;
+
+use Drupal\simpletest\TestDiscovery;
+use PHPUnit\Framework\TestSuite;
+
+/**
+ * Base class for Drupal test suites.
+ */
+abstract class Base extends TestSuite {
+
+  /**
+   * Finds extensions in a Drupal installation.
+   *
+   * An extension is defined as a directory with an *.info.yml file in it.
+   *
+   * @param string $root
+   *   Path to the root of the Drupal installation.
+   *
+   * @return string[]
+   *   Associative array of extension paths, with extension name as keys.
+   */
+  protected function findExtensionDirectories($root) {
+    $paths = [
+      $root . '/modules/custom',
+      $root . '/profiles/custom',
+      $root . '/themes/custom',
+    ];
+    $extension_roots = array_filter($paths, 'file_exists');
+
+    $extension_directories = array_map('drupal_phpunit_find_extension_directories', $extension_roots);
+    return array_reduce($extension_directories, 'array_merge', []);
+  }
+
+  /**
+   * Find and add tests to the suite for core and any extensions.
+   *
+   * @param string $root
+   *   Path to the root of the Drupal installation.
+   * @param string $suite_namespace
+   *   SubNamespace used to separate test suite. Examples: Unit, Functional.
+   */
+  protected function addTestsBySuiteNamespace($root, $suite_namespace) {
+    foreach ($this->findExtensionDirectories($root) as $extension_name => $dir) {
+      $test_path = "$dir/tests/src/$suite_namespace";
+      if (is_dir($test_path)) {
+        $this->addTestFiles(TestDiscovery::scanDirectory("Drupal\\Tests\\$extension_name\\$suite_namespace\\", $test_path));
+      }
+    }
+  }
+
+}
diff --git a/src/TestSuite/Functional.php b/src/TestSuite/Functional.php
new file mode 100644
index 0000000000000000000000000000000000000000..2e901902b16305202d9d808708bdea8222d32ad6
--- /dev/null
+++ b/src/TestSuite/Functional.php
@@ -0,0 +1,27 @@
+<?php
+
+namespace LakeDrops\Drupal8ScaffoldDeveloper\TestSuites;
+
+require_once __DIR__ . '/Base.php';
+
+/**
+ * Discovers tests for the functional test suite.
+ */
+class Functional extends Base {
+
+  /**
+   * Factory method which loads up a suite with all functional tests.
+   *
+   * @return static
+   *   The test suite.
+   */
+  public static function suite() {
+    $root = dirname(dirname(dirname(dirname(dirname(__DIR__))))) . '/web';
+
+    $suite = new static('functional');
+    $suite->addTestsBySuiteNamespace($root, 'Functional');
+
+    return $suite;
+  }
+
+}
diff --git a/src/TestSuite/FunctionalJavascript.php b/src/TestSuite/FunctionalJavascript.php
new file mode 100644
index 0000000000000000000000000000000000000000..638a09979cfe1668ee303bef1ea8b9de223ebb66
--- /dev/null
+++ b/src/TestSuite/FunctionalJavascript.php
@@ -0,0 +1,27 @@
+<?php
+
+namespace LakeDrops\Drupal8ScaffoldDeveloper\TestSuites;
+
+require_once __DIR__ . '/Base.php';
+
+/**
+ * Discovers tests for the functional test suite.
+ */
+class FunctionalJavascript extends Base {
+
+  /**
+   * Factory method which loads up a suite with all functional tests.
+   *
+   * @return static
+   *   The test suite.
+   */
+  public static function suite() {
+    $root = dirname(dirname(dirname(dirname(dirname(__DIR__))))) . '/web';
+
+    $suite = new static('functional-javascript');
+    $suite->addTestsBySuiteNamespace($root, 'FunctionalJavascript');
+
+    return $suite;
+  }
+
+}
diff --git a/src/TestSuite/Kernel.php b/src/TestSuite/Kernel.php
new file mode 100644
index 0000000000000000000000000000000000000000..e1317d36f9cde0acbfec47c0daf4bfa2f94b51ba
--- /dev/null
+++ b/src/TestSuite/Kernel.php
@@ -0,0 +1,27 @@
+<?php
+
+namespace LakeDrops\Drupal8ScaffoldDeveloper\TestSuites;
+
+require_once __DIR__ . '/Base.php';
+
+/**
+ * Discovers tests for the unit test suite.
+ */
+class Kernel extends Base {
+
+  /**
+   * Factory method which loads up a suite with all unit tests.
+   *
+   * @return static
+   *   The test suite.
+   */
+  public static function suite() {
+    $root = dirname(dirname(dirname(dirname(dirname(__DIR__))))) . '/web';
+
+    $suite = new static('kernel');
+    $suite->addTestsBySuiteNamespace($root, 'Kernel');
+
+    return $suite;
+  }
+
+}
diff --git a/src/TestSuite/Unit.php b/src/TestSuite/Unit.php
new file mode 100644
index 0000000000000000000000000000000000000000..c1dd80bb867ae3e708c7f9312bcc108f27b15457
--- /dev/null
+++ b/src/TestSuite/Unit.php
@@ -0,0 +1,27 @@
+<?php
+
+namespace LakeDrops\Drupal8ScaffoldDeveloper\TestSuites;
+
+require_once __DIR__ . '/Base.php';
+
+/**
+ * Discovers tests for the unit test suite.
+ */
+class Unit extends Base {
+
+  /**
+   * Factory method which loads up a suite with all unit tests.
+   *
+   * @return static
+   *   The test suite.
+   */
+  public static function suite() {
+    $root = dirname(dirname(dirname(dirname(dirname(__DIR__))))) . '/web';
+
+    $suite = new static('unit');
+    $suite->addTestsBySuiteNamespace($root, 'Unit');
+
+    return $suite;
+  }
+
+}
diff --git a/templates/tests/phpunit.xml.dist b/templates/tests/phpunit.xml.dist
new file mode 100644
index 0000000000000000000000000000000000000000..b1ca3d060412e0b9dea075adb54bf4a466f0e0e1
--- /dev/null
+++ b/templates/tests/phpunit.xml.dist
@@ -0,0 +1,72 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!-- TODO set checkForUnintentionallyCoveredCode="true" once https://www.drupal.org/node/2626832 is resolved. -->
+<!-- PHPUnit expects functional tests to be run with either a privileged user
+ or your current system user. See core/tests/README.md and
+ https://www.drupal.org/node/2116263 for details.
+-->
+<phpunit bootstrap="../web/core/tests/bootstrap.php" colors="true"
+         beStrictAboutTestsThatDoNotTestAnything="true"
+         beStrictAboutOutputDuringTests="true"
+         beStrictAboutChangesToGlobalState="true">
+<!-- TODO set printerClass="\Drupal\Tests\Listeners\HtmlOutputPrinter" once
+ https://youtrack.jetbrains.com/issue/WI-24808 is resolved. Drupal provides a
+ result printer that links to the html output results for functional tests.
+ Unfortunately, this breaks the output of PHPStorm's PHPUnit runner. However, if
+ using the command line you can add
+ - -printer="\Drupal\Tests\Listeners\HtmlOutputPrinter" to use it (note there
+ should be no spaces between the hyphens).
+-->
+  <php>
+    <!-- Set error reporting to E_ALL. -->
+    <ini name="error_reporting" value="32767"/>
+    <!-- Do not limit the amount of memory tests take to run. -->
+    <ini name="memory_limit" value="-1"/>
+    <!-- Example SIMPLETEST_BASE_URL value: http://localhost -->
+    <env name="SIMPLETEST_BASE_URL" value=""/>
+    <!-- Example SIMPLETEST_DB value: mysql://username:password@localhost/databasename#table_prefix -->
+    <env name="SIMPLETEST_DB" value="sqlite://localhost//tmp/test.sqlite"/>
+    <!-- Example BROWSERTEST_OUTPUT_DIRECTORY value: /path/to/webroot/sites/simpletest/browser_output -->
+    <env name="BROWSERTEST_OUTPUT_DIRECTORY" value=""/>
+    <!-- To disable deprecation testing completely uncomment the next line. -->
+    <!-- <env name="SYMFONY_DEPRECATIONS_HELPER" value="disabled"/> -->
+    <!-- Example for changing the driver class for mink tests MINK_DRIVER_CLASS value: 'Drupal\FunctionalJavascriptTests\DrupalSelenium2Driver' -->
+    <!-- Example for changing the driver args to mink tests MINK_DRIVER_ARGS value: '["http://127.0.0.1:8510"]' -->
+    <!-- Example for changing the driver args to phantomjs tests MINK_DRIVER_ARGS_PHANTOMJS value: '["http://127.0.0.1:8510"]' -->
+    <!-- Example for changing the driver args to webdriver tests MINK_DRIVER_ARGS_WEBDRIVER value: '["firefox", null, "http://localhost:4444/wd/hub"]' -->
+  </php>
+  <testsuites>
+    <testsuite name="unit">
+      <file>../vendor/lakedrops/d8-project-scaffold-developer/src/TestSuite/Unit.php</file>
+    </testsuite>
+    <testsuite name="kernel">
+      <file>../vendor/lakedrops/d8-project-scaffold-developer/src/TestSuite/Kernel.php</file>
+    </testsuite>
+    <testsuite name="functional">
+      <file>../vendor/lakedrops/d8-project-scaffold-developer/src/TestSuite/Functional.php</file>
+    </testsuite>
+    <testsuite name="functional-javascript">
+      <file>../vendor/lakedrops/d8-project-scaffold-developer/src/TestSuite/FunctionalJavascript.php</file>
+    </testsuite>
+  </testsuites>
+  <listeners>
+    <listener class="\Drupal\Tests\Listeners\DrupalListener">
+    </listener>
+    <!-- The Symfony deprecation listener has to come after the Drupal listener -->
+    <listener class="Symfony\Bridge\PhpUnit\SymfonyTestsListener">
+    </listener>
+  </listeners>
+  <!-- Filter for coverage reports. -->
+  <filter>
+    <whitelist>
+      <directory>../web/modules/custom</directory>
+      <directory>../web/profiles/custom</directory>
+      <directory>../web/themes/custom</directory>
+      <!-- By definition test classes have no tests. -->
+      <exclude>
+        <directory suffix="Test.php">./</directory>
+        <directory suffix="TestBase.php">./</directory>
+      </exclude>
+     </whitelist>
+  </filter>
+</phpunit>