You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在使用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:

  1. 创建自定义配置加载器类
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);
    }
}
  1. 在测试初始化时使用自定义加载器
    在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;
    }
}
  1. 调整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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.26 19:31:00