diff --git modules/simpletest/tests/theme.test modules/simpletest/tests/theme.test
index 9e2f387..36f877d 100644
--- modules/simpletest/tests/theme.test
+++ modules/simpletest/tests/theme.test
@@ -10,6 +10,8 @@
  * Unit tests for the Theme API.
  */
 class ThemeUnitTest extends DrupalWebTestCase {
+  protected $profile = 'testing';
+
   public static function getInfo() {
     return array(
       'name' => 'Theme API',
diff --git modules/simpletest/tests/theme_test.module modules/simpletest/tests/theme_test.module
index 63539d6..84d2901 100644
--- modules/simpletest/tests/theme_test.module
+++ modules/simpletest/tests/theme_test.module
@@ -2,6 +2,14 @@
 // $Id: theme_test.module,v 1.4 2010/08/22 12:46:21 dries Exp $
 
 /**
+ * Implements hook_system_theme_info().
+ */
+function theme_test_system_theme_info() {
+  $themes['test_theme'] = drupal_get_path('module', 'theme_test') . '/themes/test_theme/test_theme.info';
+  return $themes;
+}
+
+/**
  * Implements hook_menu().
  */
 function theme_test_menu() {
diff --git modules/simpletest/tests/themes/test_theme/template.php modules/simpletest/tests/themes/test_theme/template.php
new file mode 100644
index 0000000..5681d5b
--- /dev/null
+++ modules/simpletest/tests/themes/test_theme/template.php
@@ -0,0 +1,22 @@
+<?php
+// $Id: template.php,v 1.2 2010/08/22 12:46:21 dries Exp $
+
+/**
+ * Tests a theme overriding a suggestion of a base theme hook.
+ */
+function test_theme_breadcrumb__suggestion($variables) {
+  // Tests that preprocess functions for the base theme hook get called even
+  // when the suggestion has an implementation.
+  return 'test_theme_breadcrumb__suggestion: ' . $variables['theme_test_preprocess_breadcrumb'];
+}
+
+/**
+ * Tests a theme implementing an alter hook.
+ *
+ * The confusing function name here is due to this being an implementation of
+ * the alter hook invoked when the 'theme_test' module calls
+ * drupal_alter('theme_test_alter').
+ */
+function test_theme_theme_test_alter_alter(&$data) {
+  $data = 'test_theme_theme_test_alter_alter was invoked';
+}
diff --git modules/simpletest/tests/themes/test_theme/test_theme.info modules/simpletest/tests/themes/test_theme/test_theme.info
new file mode 100644
index 0000000..635f63f
--- /dev/null
+++ modules/simpletest/tests/themes/test_theme/test_theme.info
@@ -0,0 +1,17 @@
+; $Id: test_theme.info,v 1.3 2010/11/07 00:27:20 dries Exp $
+name = Test theme
+description = Theme for testing the theme system
+core = 7.x
+hidden = TRUE
+
+; Normally, themes may list CSS files like this, and if they exist in the theme
+; folder, then they get added to the page. If they have the same file name as a
+; module CSS file, then the theme's version overrides the module's version, so
+; that the module's version is not added to the page. Additionally, a theme may
+; have an entry like this one, without having the corresponding CSS file in the
+; theme's folder, and in this case, it just stops the module's version from
+; being loaded, and does not replace it with an alternate version. We have this
+; here in order for a test to ensure that this correctly prevents the module
+; version from being loaded, and that errors aren't caused by the lack of this
+; file within the theme folder.
+stylesheets[all][] = system.base.css
diff --git modules/system/system.api.php modules/system/system.api.php
index d50e594..d5ac10b 100644
--- modules/system/system.api.php
+++ modules/system/system.api.php
@@ -1824,6 +1824,23 @@ function hook_module_implements_alter(&$implementations, $hook) {
 }
 
 /**
+ * Return additional themes provided by modules.
+ *
+ * This hook is invoked from _system_rebuild_theme_data() and allows modules to
+ * register additional themes outside of the regular 'themes' directories of a
+ * Drupal installation. It is most commonly used to register hidden themes for
+ * testing purposes.
+ *
+ * @return
+ *   An associative array. Each key is the system name of a theme and each value
+ *   is the corresponding path to the theme's .info file.
+ */
+function hook_system_theme_info() {
+  $themes['mymodule_test_theme'] = drupal_get_path('module', 'mymodule') . '/mymodule_test_theme/mymodule_test_theme.info';
+  return $themes;
+}
+
+/**
  * Alter the information parsed from module and theme .info files
  *
  * This hook is invoked in _system_rebuild_module_data() and in
diff --git modules/system/system.module modules/system/system.module
index 89f1d48..fab9632 100644
--- modules/system/system.module
+++ modules/system/system.module
@@ -2405,6 +2405,18 @@ function _system_update_bootstrap_status() {
 function _system_rebuild_theme_data() {
   // Find themes
   $themes = drupal_system_listing('/^' . DRUPAL_PHP_FUNCTION_PATTERN . '\.info$/', 'themes');
+  // Allow modules to add further themes.
+  if ($module_themes = module_invoke_all('system_theme_info')) {
+    foreach ($module_themes as $name => $uri) {
+      // @see file_scan_directory()
+      $themes[$name] = (object) array(
+        'uri' => $uri,
+        'filename' => pathinfo($uri, PATHINFO_FILENAME),
+        'name' => $name,
+      );
+    }
+  }
+
   // Find theme engines
   $engines = drupal_system_listing('/^' . DRUPAL_PHP_FUNCTION_PATTERN . '\.engine$/', 'themes/engines');
 
diff --git modules/update/tests/themes/update_test_basetheme/update_test_basetheme.info modules/update/tests/themes/update_test_basetheme/update_test_basetheme.info
new file mode 100644
index 0000000..2a1b29b
--- /dev/null
+++ modules/update/tests/themes/update_test_basetheme/update_test_basetheme.info
@@ -0,0 +1,5 @@
+; $Id: update_test_basetheme.info,v 1.2 2010/11/07 00:27:20 dries Exp $
+name = Update test base theme
+description = Test theme which acts as a base theme for other test subthemes.
+core = 7.x
+hidden = TRUE
diff --git modules/update/tests/themes/update_test_subtheme/update_test_subtheme.info modules/update/tests/themes/update_test_subtheme/update_test_subtheme.info
new file mode 100644
index 0000000..318810e
--- /dev/null
+++ modules/update/tests/themes/update_test_subtheme/update_test_subtheme.info
@@ -0,0 +1,6 @@
+; $Id: update_test_subtheme.info,v 1.2 2010/11/07 00:27:20 dries Exp $
+name = Update test subtheme
+description = Test theme which uses update_test_basetheme as the base theme.
+core = 7.x
+base theme = update_test_basetheme
+hidden = TRUE
diff --git modules/update/tests/update_test.module modules/update/tests/update_test.module
index 1ab30b0..cea09d1 100644
--- modules/update/tests/update_test.module
+++ modules/update/tests/update_test.module
@@ -2,6 +2,15 @@
 // $Id: update_test.module,v 1.6 2010/10/05 02:17:44 dries Exp $
 
 /**
+ * Implements hook_system_theme_info().
+ */
+function update_test_system_theme_info() {
+  $themes['update_test_basetheme'] = drupal_get_path('module', 'update_test') . '/themes/update_test_basetheme/update_test_basetheme.info';
+  $themes['update_test_subtheme'] = drupal_get_path('module', 'update_test') . '/themes/update_test_subtheme/update_test_subtheme.info';
+  return $themes;
+}
+
+/**
  * Implements hook_menu().
  */
 function update_test_menu() {
diff --git themes/tests/README.txt themes/tests/README.txt
deleted file mode 100644
index 6cdb1dc..0000000
--- themes/tests/README.txt
+++ /dev/null
@@ -1,5 +0,0 @@
-// $Id: README.txt,v 1.1 2009/10/06 01:38:55 webchick Exp $
-
-The themes in this subdirectory are all used by the Drupal core testing
-framework. They are not functioning themes that could be used on a real site
-and are hidden in the administrative user interface.
diff --git themes/tests/test_theme/template.php themes/tests/test_theme/template.php
deleted file mode 100644
index 5681d5b..0000000
--- themes/tests/test_theme/template.php
+++ /dev/null
@@ -1,22 +0,0 @@
-<?php
-// $Id: template.php,v 1.2 2010/08/22 12:46:21 dries Exp $
-
-/**
- * Tests a theme overriding a suggestion of a base theme hook.
- */
-function test_theme_breadcrumb__suggestion($variables) {
-  // Tests that preprocess functions for the base theme hook get called even
-  // when the suggestion has an implementation.
-  return 'test_theme_breadcrumb__suggestion: ' . $variables['theme_test_preprocess_breadcrumb'];
-}
-
-/**
- * Tests a theme implementing an alter hook.
- *
- * The confusing function name here is due to this being an implementation of
- * the alter hook invoked when the 'theme_test' module calls
- * drupal_alter('theme_test_alter').
- */
-function test_theme_theme_test_alter_alter(&$data) {
-  $data = 'test_theme_theme_test_alter_alter was invoked';
-}
diff --git themes/tests/test_theme/test_theme.info themes/tests/test_theme/test_theme.info
deleted file mode 100644
index 635f63f..0000000
--- themes/tests/test_theme/test_theme.info
+++ /dev/null
@@ -1,17 +0,0 @@
-; $Id: test_theme.info,v 1.3 2010/11/07 00:27:20 dries Exp $
-name = Test theme
-description = Theme for testing the theme system
-core = 7.x
-hidden = TRUE
-
-; Normally, themes may list CSS files like this, and if they exist in the theme
-; folder, then they get added to the page. If they have the same file name as a
-; module CSS file, then the theme's version overrides the module's version, so
-; that the module's version is not added to the page. Additionally, a theme may
-; have an entry like this one, without having the corresponding CSS file in the
-; theme's folder, and in this case, it just stops the module's version from
-; being loaded, and does not replace it with an alternate version. We have this
-; here in order for a test to ensure that this correctly prevents the module
-; version from being loaded, and that errors aren't caused by the lack of this
-; file within the theme folder.
-stylesheets[all][] = system.base.css
diff --git themes/tests/update_test_basetheme/update_test_basetheme.info themes/tests/update_test_basetheme/update_test_basetheme.info
deleted file mode 100644
index 2a1b29b..0000000
--- themes/tests/update_test_basetheme/update_test_basetheme.info
+++ /dev/null
@@ -1,5 +0,0 @@
-; $Id: update_test_basetheme.info,v 1.2 2010/11/07 00:27:20 dries Exp $
-name = Update test base theme
-description = Test theme which acts as a base theme for other test subthemes.
-core = 7.x
-hidden = TRUE
diff --git themes/tests/update_test_subtheme/update_test_subtheme.info themes/tests/update_test_subtheme/update_test_subtheme.info
deleted file mode 100644
index 318810e..0000000
--- themes/tests/update_test_subtheme/update_test_subtheme.info
+++ /dev/null
@@ -1,6 +0,0 @@
-; $Id: update_test_subtheme.info,v 1.2 2010/11/07 00:27:20 dries Exp $
-name = Update test subtheme
-description = Test theme which uses update_test_basetheme as the base theme.
-core = 7.x
-base theme = update_test_basetheme
-hidden = TRUE
