使用Extent Report时无法从其他类获取logger.info信息的技术求助
Hey there! Let's fix that Extent Report logging issue you're dealing with. It sounds like your logger.info() messages from NewTest1 and NewTest2 aren't showing up in the HTML report generated by your Reports class in the testng package. Let's walk through the common missteps and solutions step by step.
First, let's address the core problem
Extent Report doesn't automatically capture generic logger.info() calls from other classes unless you explicitly bind those logs to an active ExtentTest instance. Most folks run into issues because they either:
- Create separate
ExtentReportsinstances in each test class (instead of a shared singleton) - Use regular Java loggers instead of Extent's native logging methods
- Fail to link test classes to the main report instance properly
Step 1: Fix your Reports class (use a singleton + ThreadLocal)
You need a centralized way to manage the ExtentReports instance and track individual test cases across threads. Here's a corrected version:
package testng; import com.aventstack.extentreports.ExtentReports; import com.aventstack.extentreports.ExtentTest; import com.aventstack.extentreports.reporter.ExtentSparkReporter; public class Reports { // Singleton ExtentReports instance (only one report created) private static ExtentReports extent; // ThreadLocal to handle parallel test execution safely private static ThreadLocal<ExtentTest> testThread = new ThreadLocal<>(); // Initialize the report once public static void initReport() { if (extent == null) { ExtentSparkReporter sparkReporter = new ExtentSparkReporter("test-output/ExtentReport.html"); extent = new ExtentReports(); extent.attachReporter(sparkReporter); // Add system info if needed extent.setSystemInfo("Environment", "QA"); extent.setSystemInfo("Tester", "Sandeep"); } } // Create a test node for each test method public static void createTest(String testName) { ExtentTest test = extent.createTest(testName); testThread.set(test); } // Get the active test instance for logging public static ExtentTest getActiveTest() { return testThread.get(); } // Finalize and save the report public static void flushReport() { if (extent != null) { extent.flush(); } } }
Step 2: Update your test classes (NewTest1/NewTest2)
Instead of using a generic logger, use the ExtentTest instance from your Reports class to log directly to the report. Here's an example for NewTest1:
package testng; import org.testng.annotations.Test; public class NewTest1 { @Test public void sampleTest1() { // Log directly to the active Extent Test node Reports.getActiveTest().info("Starting sampleTest1 in NewTest1"); // Your test logic here... Reports.getActiveTest().pass("sampleTest1 executed successfully"); } }
Step 3: Add a TestNG Listener to automate lifecycle steps
To avoid manually initializing the report and creating test nodes, use an ITestListener to hook into TestNG's test lifecycle. This keeps your test classes clean:
package testng; import org.testng.ITestContext; import org.testng.ITestListener; import org.testng.ITestResult; public class ExtentTestListener implements ITestListener { @Override public void onStart(ITestContext context) { // Initialize report when the test suite starts Reports.initReport(); } @Override public void onTestStart(ITestResult result) { // Auto-create a test node using the method name Reports.createTest(result.getMethod().getMethodName()); } @Override public void onTestSuccess(ITestResult result) { Reports.getActiveTest().pass("Test passed: " + result.getMethod().getMethodName()); } @Override public void onTestFailure(ITestResult result) { Reports.getActiveTest().fail("Test failed: " + result.getMethod().getMethodName() + "\n" + result.getThrowable()); } @Override public void onFinish(ITestContext context) { // Flush report when the test suite ends Reports.flushReport(); } }
Step 4: Register the listener in your testng.xml
Make sure TestNG uses your listener to tie everything together:
<suite name="Extent Report Suite"> <listeners> <listener class-name="testng.ExtentTestListener"/> </listeners> <test name="Sample Tests"> <classes> <class name="testng.NewTest1"/> <class name="testng.NewTest2"/> </classes> </test> </suite>
If you really need to use logger.info()
If you want to keep using your existing logger (like Log4j or java.util.logging), you can bind it to Extent Report by adding a log adapter. Add this to your Reports.initReport() method:
import com.aventstack.extentreports.logging.LogConfigurator; import java.util.logging.Logger; // Inside initReport() LogConfigurator logConfigurator = new LogConfigurator(); logConfigurator.setConfig("log4j2.xml"); // Path to your log config logConfigurator.configure(); // Bind your logger to the active ExtentTest Logger testLogger = Logger.getLogger(NewTest1.class.getName()); com.aventstack.extentreports.ExtentLogger.createLogger(testLogger, Reports.getActiveTest());
This way, your regular logger.info() calls will automatically show up in the Extent Report.
内容的提问来源于stack exchange,提问作者Sandeep

