diff --git a/core/tests/bootstrap.php b/core/tests/bootstrap.php
index 08d8871..f2358ff 100644
--- a/core/tests/bootstrap.php
+++ b/core/tests/bootstrap.php
@@ -1,21 +1,87 @@
 <?php
 
-// Register the namespaces we'll need to autoload from.
+/**
+ * @file
+ * Autoloader for Drupal PHPUnit testing.
+ *
+ * @see phpunit.xml.dist
+ */
+
+/**
+ * Recursively scan a directory for modules to autoload.
+ *
+ * For our purposes here, a module is considered to be
+ * a directory with a /lib subdirectory.
+ *
+ * @param ComposerAutoloader $loader
+ *   The supplied autoloader.
+ * @param string $given_path
+ *   The path to recursively scan.
+ */
+function _drupal_phpunit_scan_autoload_directories($loader, $given_path) {
+  // Make sure we ignore . and .. directories.
+  if (in_array(basename($given_path), array('.', '..'))) {
+    return;
+  }
+  if (is_dir($given_path)) {
+    $items = scandir($given_path);
+    foreach($items as $item) {
+      $child_path = "$given_path/$item";
+      // We only care about directories.
+      if (is_dir($child_path)) {
+        // Recursion first.
+        _drupal_phpunit_scan_autoload_directories($loader, $child_path);
+        // Check if it's a module second.
+        $lib_path = $child_path . '/lib';
+        $info_yml = $child_path . "/$item.info.yml";
+        if (is_dir($lib_path) && is_file($info_yml)) {
+          $loader->add('Drupal\\' . $item, $lib_path);
+        }
+      }
+    }
+  }
+}
+
+/**
+ * Start scanning for module namespaces to autoload.
+ *
+ * @param ComposerAutoloader $loader
+ *   The supplied autoloader.
+ */
+function _drupal_phpunit_autoload_scan($loader) {
+  // Some easy places to look.
+  $scan_these_directories = array(
+    __DIR__ . "/../modules",
+    __DIR__ . "/../../modules",
+  );
+  // Add all the /sites subfolders, ruling out sites/*/files.
+  $sites_dir = __DIR__ . "/../../sites";
+  $site_folders = scandir($sites_dir);
+  // Scan through the multisite folders.
+  foreach($site_folders as $item) {
+    if (is_dir("$sites_dir/$item") && !in_array($item, array('.', '..'))) {
+      $multisite_subfolders = scandir("$sites_dir/$item");
+      foreach($multisite_subfolders as $subitem) {
+        // Rule out /sites/*/files
+        if ($subitem != 'files') {
+          $scan_these_directories[] = "$sites_dir/$item/$subitem";
+        }
+      }
+    }
+  }
+  foreach($scan_these_directories as $path) {
+    _drupal_phpunit_scan_autoload_directories($loader, $path);
+  }
+}
+
+// Start with classes in known locations.
 $loader = require __DIR__ . "/../vendor/autoload.php";
 $loader->add('Drupal\\', __DIR__);
 $loader->add('Drupal\Core', __DIR__ . "/../../core/lib");
 $loader->add('Drupal\Component', __DIR__ . "/../../core/lib");
 
-foreach (scandir(__DIR__ . "/../modules") as $module) {
-  $loader->add('Drupal\\' . $module, __DIR__ . "/../modules/" . $module . "/lib");
-  // Add test module classes.
-  $test_modules_dir = __DIR__ . "/../modules/$module/tests/modules";
-  if (is_dir($test_modules_dir)) {
-    foreach (scandir($test_modules_dir) as $test_module) {
-      $loader->add('Drupal\\' . $test_module, $test_modules_dir . '/' . $test_module . '/lib');
-    }
-  }
-}
+// Scan for arbitrary module namespaces.
+_drupal_phpunit_autoload_scan($loader);
 
 require __DIR__ . "/../../core/lib/Drupal.php";
 // Look into removing this later.
