diff --git a/scripts/run-tests.sh b/scripts/run-tests.sh
index a42215e..ddce3f9 100755
--- a/scripts/run-tests.sh
+++ b/scripts/run-tests.sh
@@ -100,6 +100,10 @@ if ($args['xml']) {
   simpletest_script_reporter_write_xml_results();
 }
 
+if ($args['junit']) {
+  simpletest_script_reporter_write_junit_results();
+}
+
 // Cleanup our test results.
 simpletest_clean_results_table($test_id);
 
@@ -151,6 +155,10 @@ All arguments are long options.
   --xml       <path>
 
               If provided, test results will be written as xml files to this path.
+              
+  --junit     <path>
+
+              If provided, test results will be written as junit files to this path.
 
   --color     Output text format results with color highlighting.
 
@@ -204,6 +212,7 @@ function simpletest_script_parse_args() {
     'test-id' => 0,
     'execute-test' => '',
     'xml' => '',
+    'junit' => '',
   );
 
   // Override with set values.
@@ -650,6 +659,138 @@ function simpletest_script_reporter_write_xml_results() {
 }
 
 /**
+ * Display jenkins-friendly jUnit XML test results.
+ */
+function simpletest_script_reporter_write_junit_results() {
+  global $args, $test_id, $results_map;
+
+  $results = db_query("SELECT * FROM {simpletest} WHERE test_id = :test_id ORDER BY test_class, message_id", array(':test_id' => $test_id));
+
+  $test_class = '';
+  $xml_files = array();
+
+  // Collect and aggregate the data from simpletest.
+  $test_suites = array();
+  foreach ($results as $result) {
+    // Create test_suite object.
+    // Formatting name so it becomes "group.name" without any other dots. Jenkins uses string splitting on dots to gather info.
+    $info = call_user_func(array($result->test_class, 'getInfo'));
+    $test_suite_name = str_replace('.', '', $info['group']) . '.' . str_replace('.', '', $info['name']);
+    if (!isset($test_suites[$test_suite_name])) {
+      $test_suite = new stdClass();
+      $test_suite->test_class = $result->test_class;
+      $test_suite->tests = 0;
+      $test_suite->disabled = 0;
+      $test_suite->errors = 0;
+      $test_suite->failures = 0;
+      $test_suite->skipped = 0;
+      $test_suite->test_cases = array();
+      $test_suites[$test_suite_name] = $test_suite;
+    }
+    else {
+      $test_suite = $test_suites[$test_suite_name];
+      $test_suite->tests++;
+    }
+    // Create test_case object.
+    list(, $test_case_name) = explode('->', $result->function, 2);
+    if (empty($test_case_name)) {
+      // There is no '->' present on static function calls. Use the whole string in those cases.
+      $test_case_name = $result->function;
+    }
+    $test_case_name = str_replace('.', '', $test_case_name);  // Remove those dots Jenkins loves so much.
+    if (!isset($test_suite->test_cases[$test_case_name])) {
+      $test_case = new stdClass();
+      $test_case->name = $test_case_name;
+      $test_case->assertions = 0;
+      $test_case->classname = $test_suite_name;
+      $test_case->status = 'pass';
+      $test_case->failure_message = array();
+      $test_case->error_message = array();
+      $test_case->system_out = '';
+      $test_case->system_err = '';
+      $test_suite->test_cases[$test_case_name] = $test_case;
+    }
+    else {
+      $test_case = $test_suite->test_cases[$test_case_name];
+    }
+    $test_case->assertions++;
+    // Prepare message.
+    $status = str_pad($result->status . ':', 10);
+    $message = strip_tags($result->message, '<a>');  // Jenkins encodes the output so don't use any tags.
+    $message = preg_replace('/<a.*?href="([^"]+)".*?>(.*?)<\/a>/', '$1 $2', $message); // Jenkins will turn urls into clickable links.
+    $message = $status . ' [' . $result->message_group . '] ' . $message . ' [' . basename($result->file) . ':' . $result->line . "]\n";
+    
+    // Everything else is logged in system_out.
+    $test_case->system_out .= $message;
+    // Failures go to failures.
+    if ($result->status == 'fail') {
+      $test_case->status = 'failed';
+      $test_suite->failures++;
+      $test_case->failure_message[] = $message;
+    }
+    // Exceptions go both to errors and system_err.
+    if ($result->status == 'exception') {
+      $test_suite->errors++;
+      $test_case->error_message[] = $message;
+      //$test_case->system_err .= $message;
+    }
+
+    $test_suite->test_cases[$test_case_name] = $test_case;
+  }
+
+  // Build an XML document from our results.
+  foreach ($test_suites as $test_suite_name => $test_suite) {
+    $xml = new DOMDocument('1.0', 'UTF-8');
+    $xml->preserveWhiteSpace = false;
+    $xml->formatOutput = true;
+    $test_suite_element = $xml->createElement('testsuite');
+    //$test_suite_element->setAttribute('name', $test_suite_name);
+    $test_suite_element->setAttribute('tests', $test_suite->tests);
+    $test_suite_element->setAttribute('disabled', $test_suite->disabled);
+    $test_suite_element->setAttribute('errors', $test_suite->errors);
+    $test_suite_element->setAttribute('failures', $test_suite->failures);
+    foreach ($test_suite->test_cases as $test_case_name => $test_case) {
+      $test_case_element = $xml->createElement('testcase');
+      $test_case_element->setAttribute('name', $test_case->name);
+      $test_case_element->setAttribute('assertions', $test_case->assertions);
+      $test_case_element->setAttribute('classname', $test_case->classname);
+      $test_case_element->setAttribute('status', $test_case->status);
+      //$test_case_element->setAttribute('time', $test_case->time);
+      if (!empty($test_case->failure_message)) {
+        $failure_element = $xml->createElement('failure');
+        $failure_element->setAttribute('type', 'fail');
+        $failure_element->setAttribute('message', 'Number of failed assertions: ' . count($test_case->failure_message));
+        $failure_element->appendChild($xml->createCDATASection(implode('', $test_case->failure_message)));
+        $test_case_element->appendChild($failure_element);
+      }
+      if (!empty($test_case->error_message)) {
+        $error_element = $xml->createElement('error');
+        $error_element->setAttribute('type', 'exception');
+        $error_element->setAttribute('message', 'Number of unexpected errors: ' . count($test_case->error_message));
+        $error_element->appendChild($xml->createCDATASection(implode('', $test_case->error_message)));
+        $test_case_element->appendChild($error_element);
+      }
+      if (!empty($test_case->system_out)) {
+        $system_out_element = $xml->createElement('system-out');
+        $system_out_element->appendChild($xml->createCDATASection($test_case->system_out));
+        $test_case_element->appendChild($system_out_element);
+      }
+      if (!empty($test_case->system_err)) {
+        $system_err_element = $xml->createElement('system-err');
+        $system_err_element->appendChild($xml->createCDATASection($test_case->system_err));
+        $test_case_element->appendChild($system_err_element);
+      }
+      $test_suite_element->appendChild($test_case_element);
+    }
+
+    $xml->appendChild($test_suite_element);
+    // Save to disk.
+    file_put_contents($args['junit'] . '/' . $test_suite->test_class . '.junit.xml', $xml->saveXML());
+    unset($xml);
+  }
+}
+
+/**
  * Stop the test timer.
  */
 function simpletest_script_reporter_timer_stop() {
