JMeter中使用Extent Report仅显示最后一个采样器结果问题求助
问题:JMeter集成ExtentReport 5.0.6仅显示最后一个采样器结果
我正在使用JMeter进行API功能自动化测试,尝试用ExtentReport 5.0.6生成测试报告,但报告结果被覆盖,仅显示最后一个执行的采样器。我的配置如下:
当前配置代码
每个ThreadGroup根节点的Beanshell Assertion代码
//request data String requestData = new String(prev.SamplerData); //String requestData = new String(requestData); props.put("propRequestData", requestData); //response data String respData = new String(prev.ResponseData); //String respData = new String(prev.getResponseDataAsString()); props.put("propResponse", respData); //response code String respCode = new String(prev.ResponseCode); props.put("propRespCode",respCode); //response message String respMessage = new String(prev.ResponseMessage); props.put("propRespMessage",respMessage);
测试计划根节点的JSR223 Listener代码
import com.aventstack.extentreports.*; import com.aventstack.extentreports.reporter.*; import com.aventstack.extentreports.markuputils.*; import com.aventstack.extentreports.reporter.configuration.ViewName; ExtentSparkReporter htmlReporter; ExtentReports extent; ExtentTest extentTest; if(extent == null) { // create the HtmlReporter htmlReporter = new ExtentSparkReporter("C:/API-Results.html"); //configure report htmlReporter.config().setOfflineMode(true); //htmlReporter.config().setChartVisibilityOnOpen(true); htmlReporter.config().setDocumentTitle("Results"); htmlReporter.config().setEncoding("utf-8"); htmlReporter.config().setReportName("CKPAT API Results"); htmlReporter.viewConfigurer().viewOrder().as(new ViewName[] {ViewName.DASHBOARD, ViewName.TEST}).apply(); // create ExtentReports extent = new ExtentReports(); // attach reporter to ExtentReports extent.attachReporter(htmlReporter); extent.setReportUsesManualConfiguration(true); // Show Env section and set data on dashboard extent.setSystemInfo("Tool","JMeter"); extent.setSystemInfo("Environment", "QA"); } //extent.setSystemInfo("Test Time","${currentTime}"); //stringify test info String threadName = sampler.getThreadName(); String samplerName = sampler.getName(); String requestData = props.get("propRequestData"); String respCode = props.get("propRespCode"); String respMessage = props.get("propRespMessage"); String responseData = props.get("propResponse"); // create test extentTest = extent.createTest(threadName+" - "+samplerName); //test.assignCategory("API Testing"); // analyze sampler result if (vars.get("JMeterThread.last_sample_ok") == "false") { log.error("FAILED: "+samplerName); print("FAILED: "+samplerName); extentTest.fail(MarkupHelper.createLabel("FAILED: "+sampler.getName(),ExtentColor.RED)); } else if (vars.get("JMeterThread.last_sample_ok") == "true") { if(responseData.contains("@error")) { log.info("FAILED: "+sampler.getName()); print("FAILED: "+sampler.getName()); extentTest.fail(MarkupHelper.createLabel("FAILED: "+sampler.getName(),ExtentColor.RED)); } else if (responseData.contains("{")) { log.info("Passed: "+sampler.getName()); print("Passed: "+sampler.getName()); extentTest.pass(MarkupHelper.createLabel("Passed: "+sampler.getName(),ExtentColor.GREEN)); } } else { log.error("Something is really wonky"); print("Something is really wonky"); extentTest.fatal("Something is really wonky"); } //info messages extentTest.info("RequestData: "+requestData); extentTest.info("Response Code and Message: "+respCode+" "+respMessage); extentTest.info("ResponseData: "+responseData); extent.flush();
问题原因分析
- ExtentReports对象未持久化:JSR223 Listener中的
extent是脚本局部变量,每次采样器触发监听器时,脚本重新执行,extent都会被重置为null,导致每次都重新创建ExtentReports对象,覆盖之前的报告文件。 - 全局props数据被覆盖:
props是JMeter全局属性,每个采样器执行时都会用新数据覆盖同一个key的值,最终监听器只能获取到最后一个采样器的请求/响应数据。 - 频繁调用extent.flush():每个采样器后都执行flush,可能导致报告写入不完整,且加重IO负担。
解决方案
1. 持久化ExtentReports对象到全局属性
修改JSR223 Listener的初始化逻辑,将extent存入全局props,确保整个测试仅初始化一次:
import com.aventstack.extentreports.*; import com.aventstack.extentreports.reporter.*; import com.aventstack.extentreports.markuputils.*; import com.aventstack.extentreports.reporter.configuration.ViewName; ExtentSparkReporter htmlReporter; ExtentReports extent; ExtentTest extentTest; // 从全局props获取已初始化的extent,不存在则创建 if (props.get("extent") == null) { htmlReporter = new ExtentSparkReporter("C:/API-Results.html"); // 配置报告 htmlReporter.config().setOfflineMode(true); htmlReporter.config().setDocumentTitle("Results"); htmlReporter.config().setEncoding("utf-8"); htmlReporter.config().setReportName("CKPAT API Results"); htmlReporter.viewConfigurer().viewOrder().as(new ViewName[] {ViewName.DASHBOARD, ViewName.TEST}).apply(); extent = new ExtentReports(); extent.attachReporter(htmlReporter); extent.setReportUsesManualConfiguration(true); // 设置系统信息 extent.setSystemInfo("Tool","JMeter"); extent.setSystemInfo("Environment", "QA"); // 存入全局props,避免重复初始化 props.put("extent", extent); } else { extent = props.get("extent"); }
2. 改用线程局部变量存储采样器数据
将Beanshell Assertion中的props替换为vars(线程局部变量,不会跨线程/采样器覆盖):
//request data String requestData = new String(prev.SamplerData); vars.put("propRequestData", requestData); //response data String respData = new String(prev.ResponseData); vars.put("propResponse", respData); //response code String respCode = new String(prev.ResponseCode); vars.put("propRespCode",respCode); //response message String respMessage = new String(prev.ResponseMessage); vars.put("propRespMessage",respMessage);
同时修改JSR223 Listener中获取数据的方式:
// 获取采样器数据(改用vars) String requestData = vars.get("propRequestData"); String respCode = vars.get("propRespCode"); String respMessage = vars.get("propRespMessage"); String responseData = vars.get("propResponse");
3. 调整extent.flush()执行时机
删除原JSR223 Listener中的extent.flush();语句,添加JSR223 Test Listener到测试计划根节点,在测试结束时统一执行flush:
import com.aventstack.extentreports.ExtentReports; ExtentReports extent = props.get("extent"); if (extent != null) { extent.flush(); }
4. 优化结果判断逻辑
改用prev.isSuccessful()替代vars.get("JMeterThread.last_sample_ok"),逻辑更可靠:
// 分析采样器结果 if (!prev.isSuccessful()) { log.error("FAILED: " + samplerName); print("FAILED: " + samplerName); extentTest.fail(MarkupHelper.createLabel("FAILED: " + sampler.getName(), ExtentColor.RED)); } else { if (responseData.contains("@error")) { log.info("FAILED: " + sampler.getName()); print("FAILED: " + sampler.getName()); extentTest.fail(MarkupHelper.createLabel("FAILED: " + sampler.getName(), ExtentColor.RED)); } else { log.info("Passed: " + sampler.getName()); print("Passed: " + sampler.getName()); extentTest.pass(MarkupHelper.createLabel("Passed: " + sampler.getName(), ExtentColor.GREEN)); } }
验证修改
执行测试后,ExtentReport将包含所有采样器的执行结果,不会再出现覆盖问题。
内容的提问来源于stack exchange,提问作者Maithili Srinivasan
相关产品推荐
相关产品推荐

