It works fine, from multi-threaded tests to the HTML report because the ITestResult is always the same in the end, no matter what you do. You can simple create a "CustomReport" class that extends IReporter. Then, override the generateReport method and just let TestNG create and pass these 2 arguments into it:
@Override
public void generateReport( List<XmlSuite> xml, List<ISuite> suites, String outdir )
{
for ( ISuite thisSuite: suites ) {
thisSuite.getResults(). ...
...
}
....
Then, inside that method, do what you will, to customize the report and generate HTML tables or whatever.
Also, one thing I do (to reduce confusion in the console output while multithreaded tests run) is log the thread name to messages on the TestNG report by using something like:
public void logIt( String message ) {
Reporter.log( "Thread-" + Thread.currentThread().getId() + ": " + message, true );
}
TestNG is awesome, especially when you understand what I said above as well as the fact that you implicitly allow TestNG to pass a XMLTest or ITestContext or ITestResult to some of the @Configuration methods. For example:
@BeforeClass
public void setUp( ITestContext context ) {
logger.info("BeforeClass setUp...");
suiteParams = context.getSuite().getXmlSuite().getAllParameters();
...