unclebob/fitnesse — pull request #544 by amolenaar (2014-10-26 14:14:12+00:00)
Title: NullPointerException in JavaFormatter

java.lang.NullPointerException: null
at fitnesse.junit.JavaFormatter$FolderResultsRepository.write(JavaFormatter.java:106)
at fitnesse.junit.JavaFormatter.testOutputChunk(JavaFormatter.java:156)
at fitnesse.testsystems.CompositeTestSystemListener.testOutputChunk(CompositeTestSystemListener.java:28)
at fitnesse.testrunner.MultipleTestsRunner$InternalTestSystemListener.testOutputChunk(MultipleTestsRunner.java:201)
at fitnesse.testrunner.MultipleTestsRunner.startTestSystem(MultipleTestsRunner.java:166)
at fitnesse.testrunner.MultipleTestsRunner.startTestSystemAndExecutePages(MultipleTestsRunner.java:99)
at fitnesse.testrunner.MultipleTestsRunner.internalExecuteTestPages(MultipleTestsRunner.java:88)
at fitnesse.testrunner.MultipleTestsRunner.executeTestPages(MultipleTestsRunner.java:70)
at fitnesse.junit.FitNesseRunner.executeTests(FitNesseRunner.java:391)
at fitnesse.junit.FitNesseRunner.runPages(FitNesseRunner.java:336)
at fitnesse.junit.FitNesseRunner.run(FitNesseRunner.java:318)

This error happens (sometimes!) when running Fitnesse test suite from JUnit using FitNesseRunner annotation. Analyzing code shows that exception in JavaFormatter happens when Fitnesse tries to write another exception in catch {} block:

fitnesse.testrunner.MultipleTestsRunner.startTestSystem(MultipleTestsRunner.java:166)

...
try {
testSystem = testSystemFactory.create(descriptor);
testSystem.addTestSystemListener(internalTestSystemListener);
testSystem.start();
} catch (Exception e) {
internalTestSystemListener.testOutputChunk(String.format("Unable to start test system '%s': %s", descriptor.getTestSystem(), e.toString()));
return null;
}
...

Problem is that JavaFormatter instance kept in MultipleTestsRunner.formatters is not ready to write any info at this moment - testSystem was not started and JavaFormatter#FolderResultsRepository.testResultPage property is not initialized via JavaFormatter#FolderResultsRepository.open(String testName) method.
This would happen if testSystem started successfully and JavaFormatted#testStarted event occurred - but this is not the case since something has failed before.

So NPE described in this issue hides attempt to write another exception that is completely swallowed.

Possible fix for NPE depends if its desired behavior to write exceptions info into JavaFormatter used to write test results.

As minimum fix, to prevent hiding original exceptions - logging could be added here:

} catch (Exception e) {
LOG.log(Level.WARNING, "Unable to start test system", e);
internalTestSystemListener.testOutputChunk(String.format("Unable to start test system '%s': %s", descriptor.getTestSystem(), e.toString()));
return null;
}

Thanks in advance.