如何在使用ExtendCucumberAdapter时从Jar中读取extent-config.xml
问题描述
通过Cucumber CLI运行打包后的Jar时,出现FileNotFoundException——ExtendCucumberAdapter依赖的XmlConfigLoader使用FileInputStream无法读取Jar包内的extent-config.xml资源。希望实现无需依赖外部文件系统即可运行Jar,需求是要么让ExtentReports直接读取Jar内的配置文件,要么在运行时自动从Jar复制该文件到文件系统。
项目结构
project-root │ ├── src │ ├── main │ │ └── java │ │ └── com.example.package │ │ └── Main.java (Cucumber CLI usage) │ └── test │ ├── java │ │ └── com.example.package │ │ └── runner │ │ └── YourTestRunner.java (Test Runner class) │ │ └── stepdefinition │ │ └── YourStepDefinitions.java (Cucumber step definitions) │ └── resources │ └── features │ └── your.feature |___extent.properties |___extent-config.xml
Jar结构
|-META-INF |-com |-extent-config.xml
核心代码与配置
Main.java
package com.example; import io.cucumber.core.cli.Main; public class Main { public static void main(String[] args) throws Throwable { String[] cucumberArgs = { "--glue", "com.example.package.runner.YourTestRunner", "--glue", "com.example.package.stepdefinition", "classpath:/features", "-t", "@mytag", "-p", "com.aventstack.extentreports.cucumber.adapter.ExtendCucumberAdapter:", "-p","json:test/output.json", "-p","html:test/output2.html" }; Main.run(cucumberArgs, Thread.currentThread().getContextClassLoader()); } }
extent.properties
extent.reporter.html.start=true extent.reporter.logger.start=true extent.reporter.spark.start=true extent.reporter.html.config=extent-config.xml extent.reporter.logger.config=extent-config.xml extent.reporter.spark.config=extent-config.xml
运行命令
java -jar custom-jar-name.jar
解决方案
方案一:直接读取Jar内的配置资源
部分新版本的ExtentReports支持通过classpath:前缀加载类路径资源,如果你的版本支持,只需修改配置即可;若不支持,则需要自定义配置加载逻辑。
方法1:利用classpath前缀(推荐,版本兼容时使用)
修改extent.properties中的配置路径,添加classpath:前缀:
extent.reporter.html.start=true extent.reporter.logger.start=true extent.reporter.spark.start=true extent.reporter.html.config=classpath:extent-config.xml extent.reporter.logger.config=classpath:extent-config.xml extent.reporter.spark.config=classpath:extent-config.xml
这样ExtentReports会通过类加载器读取Jar内的资源,无需依赖外部文件。
方法2:自定义配置加载器(兼容旧版本)
如果你的ExtentReports版本不支持classpath:前缀,可通过自定义加载器替换默认的XmlConfigLoader:
- 创建自定义配置加载器类
import com.aventstack.extentreports.reporter.configuration.XmlConfigLoader; import java.io.InputStream; public class JarResourceXmlConfigLoader extends XmlConfigLoader { public JarResourceXmlConfigLoader(String resourcePath) { super(getResourceStream(resourcePath)); } private static InputStream getResourceStream(String resourcePath) { return Thread.currentThread().getContextClassLoader().getResourceAsStream(resourcePath); } }
- 在测试初始化时使用自定义加载器
在TestRunner或启动类中,手动初始化ExtentReporter并加载Jar内的配置流:
import com.aventstack.extentreports.ExtentReports; import com.aventstack.extentreports.reporter.ExtentSparkReporter; import java.io.InputStream; public class ExtentReportManager { private static ExtentReports extent; public static ExtentReports getInstance() { if (extent == null) { ExtentSparkReporter sparkReporter = new ExtentSparkReporter("test/output.html"); // 从Jar内读取配置流 InputStream configStream = Thread.currentThread().getContextClassLoader().getResourceAsStream("extent-config.xml"); sparkReporter.loadXMLConfig(configStream); extent = new ExtentReports(); extent.attachReporter(sparkReporter); } return extent; } }
- 调整Cucumber运行逻辑
不再依赖默认的ExtendCucumberAdapter,而是在步骤定义中直接调用ExtentReportManager记录测试结果,或者自定义适配器集成该逻辑。
方案二:运行时复制配置文件到文件系统
如果无法修改ExtentReports的加载逻辑,可在程序启动时将Jar内的配置文件复制到本地文件系统,让ExtentReports读取本地文件:
修改Main.java,添加复制逻辑
package com.example; import io.cucumber.core.cli.Main; import java.io.*; public class Main { public static void main(String[] args) throws Throwable { // 将Jar内的extent-config.xml复制到当前目录 copyResourceToFile("extent-config.xml", "./extent-config.xml"); String[] cucumberArgs = { "--glue", "com.example.package.runner.YourTestRunner", "--glue", "com.example.package.stepdefinition", "classpath:/features", "-t", "@mytag", "-p", "com.aventstack.extentreports.cucumber.adapter.ExtendCucumberAdapter:", "-p","json:test/output.json", "-p","html:test/output2.html" }; Main.run(cucumberArgs, Thread.currentThread().getContextClassLoader()); } private static void copyResourceToFile(String resourcePath, String targetPath) throws IOException { try (InputStream in = Thread.currentThread().getContextClassLoader().getResourceAsStream(resourcePath); OutputStream out = new FileOutputStream(targetPath)) { if (in == null) { throw new FileNotFoundException("未找到资源: " + resourcePath); } byte[] buffer = new byte[1024]; int bytesRead; while ((bytesRead = in.read(buffer)) != -1) { out.write(buffer, 0, bytesRead); } } } }
保持原配置不变
extent.properties无需修改,因为复制后的文件会存放在当前目录,与原配置路径匹配。
内容的提问来源于stack exchange,提问作者Amit Kumar
相关产品推荐
相关产品推荐

