diff --git a/src/unit/engine/PhpunitTestEngine.php b/src/unit/engine/PhpunitTestEngine.php
--- a/src/unit/engine/PhpunitTestEngine.php
+++ b/src/unit/engine/PhpunitTestEngine.php
@@ -52,7 +52,7 @@
       if (!Filesystem::pathExists($test_path)) {
         continue;
       }
-      $json_tmp = new TempFile();
+      $xml_tmp = new TempFile();
       $clover_tmp = null;
       $clover = null;
       if ($this->getEnableCoverage() !== false) {
@@ -64,10 +64,10 @@
 
       $stderr = '-d display_errors=stderr';
 
-      $futures[$test_path] = new ExecFuture('%C %C %C --log-json %s %C %s',
-        $this->phpunitBinary, $config, $stderr, $json_tmp, $clover, $test_path);
+      $futures[$test_path] = new ExecFuture('%C %C %C --log-junit %s %C %s',
+        $this->phpunitBinary, $config, $stderr, $xml_tmp, $clover, $test_path);
       $tmpfiles[$test_path] = array(
-        'json' => $json_tmp,
+        'xml' => $xml_tmp,
         'clover' => $clover_tmp,
       );
     }
@@ -81,7 +81,7 @@
 
       $results[] = $this->parseTestResults(
         $test,
-        $tmpfiles[$test]['json'],
+        $tmpfiles[$test]['xml'],
         $tmpfiles[$test]['clover'],
         $stderr);
     }
@@ -99,8 +99,8 @@
    *
    * @return array
    */
-  private function parseTestResults($path, $json_tmp, $clover_tmp, $stderr) {
-    $test_results = Filesystem::readFile($json_tmp);
+  private function parseTestResults($path, $xml_tmp, $clover_tmp, $stderr) {
+    $test_results = Filesystem::readFile($xml_tmp);
     return id(new ArcanistPhpunitTestResultParser())
       ->setEnableCoverage($this->getEnableCoverage())
       ->setProjectRoot($this->projectRoot)
diff --git a/src/unit/parser/ArcanistPhpunitTestResultParser.php b/src/unit/parser/ArcanistPhpunitTestResultParser.php
--- a/src/unit/parser/ArcanistPhpunitTestResultParser.php
+++ b/src/unit/parser/ArcanistPhpunitTestResultParser.php
@@ -25,80 +25,19 @@
       return array($result);
     }
 
-    $report = $this->getJsonReport($test_results);
-
     // coverage is for all testcases in the executed $path
     $coverage = array();
     if ($this->enableCoverage !== false) {
       $coverage = $this->readCoverage();
     }
 
-    $last_test_finished = true;
-
-    $results = array();
-    foreach ($report as $event) {
-      switch (idx($event, 'event')) {
-      case 'test':
-        break;
-      case 'testStart':
-        $last_test_finished = false;
-        // fall through
-        default:
-          continue 2; // switch + loop
-      }
-
-      $status = ArcanistUnitTestResult::RESULT_PASS;
-      $user_data = '';
+    $xunit_result_parser = new ArcanistXUnitTestResultParser();
+    $results = $xunit_result_parser->parseTestResults($test_results);
 
-      if ('fail' == idx($event, 'status')) {
-        $status = ArcanistUnitTestResult::RESULT_FAIL;
-        $user_data  .= idx($event, 'message')."\n";
-        foreach (idx($event, 'trace') as $trace) {
-          $user_data .= sprintf(
-            "\n%s:%s",
-            idx($trace, 'file'),
-            idx($trace, 'line'));
-        }
-      } else if ('error' == idx($event, 'status')) {
-        if (strpos(idx($event, 'message'), 'Skipped Test') !== false) {
-          $status = ArcanistUnitTestResult::RESULT_SKIP;
-          $user_data .= idx($event, 'message');
-        } else if (strpos(
-            idx($event, 'message'),
-            'Incomplete Test') !== false) {
-          $status = ArcanistUnitTestResult::RESULT_SKIP;
-          $user_data .= idx($event, 'message');
-        } else {
-          $status = ArcanistUnitTestResult::RESULT_BROKEN;
-          $user_data  .= idx($event, 'message');
-          foreach (idx($event, 'trace') as $trace) {
-            $user_data .= sprintf(
-              "\n%s:%s",
-              idx($trace, 'file'),
-              idx($trace, 'line'));
-          }
-        }
-      }
-
-      $name = preg_replace('/ \(.*\)/s', '', idx($event, 'test'));
-
-      $result = new ArcanistUnitTestResult();
-      $result->setName($name);
-      $result->setResult($status);
-      $result->setDuration(idx($event, 'time'));
+    foreach ($results as $result) {
       $result->setCoverage($coverage);
-      $result->setUserData($user_data);
-
-      $results[] = $result;
-      $last_test_finished = true;
     }
 
-    if (!$last_test_finished) {
-      $results[] = id(new ArcanistUnitTestResult())
-        ->setName(idx($event, 'test')) // use last event
-        ->setUserData($this->stderr)
-        ->setResult(ArcanistUnitTestResult::RESULT_BROKEN);
-    }
     return $results;
   }
 
@@ -161,28 +100,4 @@
     return $reports;
   }
 
-  /**
-   * We need this non-sense to make json generated by phpunit
-   * valid.
-   *
-   * @param string $json String containing JSON report
-   * @return array JSON decoded array
-   */
-  private function getJsonReport($json) {
-
-    if (empty($json)) {
-      throw new Exception(
-        pht(
-          'JSON report file is empty, it probably means that phpunit '.
-          'failed to run tests. Try running %s with %s option and then run '.
-          'generated phpunit command yourself, you might get the answer.',
-          'arc unit',
-          '--trace'));
-    }
-
-    $json = preg_replace('/}{\s*"/', '},{"', $json);
-    $json = '['.$json.']';
-    return phutil_json_decode($json);
-  }
-
 }