调试阶段,我们通常直接在 IDEA 里 Run 测试,控制台输出的信息零散、易被刷屏,断言失败时只能看到一行堆栈,难以快速定位是哪个用例、哪一步、哪组数据出了问题;即使测试全部通过,也看不出用例的覆盖范围与执行趋势。相比之下,一份结构化、可视化的测试报告能直观呈现每个用例的执行结果、步骤明细、请求响应和失败截图,让问题一目了然,也便于团队共享与回溯。因此,在现有框架中引入 Allure 来生成 Report,把"跑完看控制台"升级为"跑完看报告"。
注:本项目需要下载allure到本地
一、相关文件清单与对应职责
| 文件 | 职责 |
|---|---|
pom.xml |
依赖、surefire 配置(argLine + systemPropertyVariables)、clean 配置 |
testng.xml |
注册 AllureReportListener |
AllureReportListener.java |
suite 结束时调 allure.bat 生成时间戳报告 |
AbstractCaseTest.java |
Allure.getLifecycle().updateTestCase 改报告显示名 |
ResponseAsserter.java |
@Step 注解,靠 aspectjweaver 生效 |
target/allure-results/ |
运行时产物,不是源码 |
report/<时间戳>/ |
最终 HTML 报告,不是源码 |
二、具体代码和详细说明
1. Pom.xml - 配置层
| 位置 | 作用 |
|---|---|
<properties> 里 allure.results.directory |
结果目录,target/allure-results |
依赖 io.qameta.allure:allure-testng |
提供 TestNG 集成,运行时自动生成结果文件 |
依赖 org.aspectj:aspectjweaver |
关键,Allure 的 @Step、@Attachment 靠它做字节码织入,没它注解不生效 |
maven-clean-plugin |
clean 时删掉 target/allure-results |
maven-surefire-plugin |
指定 testng.xml、控制 fork、挂 aspectjweaver javaagent、传 allure.results.directory 系统属性 |
xml
<properties>
<aspectj.version>1.9.21</aspectj.version>
<!-- allure 结果目录 -->
<allure.results.directory>${project.build.directory}/allure-results</allure.results.directory>
</properties>
<dependencies>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>${aspectj.version}</version>
</dependency>
<dependency>
<groupId>io.qameta.allure</groupId>
<artifactId>allure-testng</artifactId>
<version>${allure.version}</version>
</dependency>
</dependencies>
<build>
<plugins>
<!-- clean 时只清 allure 结果目录(report/<时间戳> 由 Listener 生成,不在这里清) -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-clean-plugin</artifactId>
<version>${maven.clean.plugin.version}</version>
<configuration>
<filesets>
<fileset>
<directory>${allure.results.directory}</directory>
</fileset>
</filesets>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>${maven.surefire.plugin.version}</version>
<configuration>
<suiteXmlFiles>
<suiteXmlFile>testng.xml</suiteXmlFile>
</suiteXmlFiles>
<useFile>false</useFile>
<reportFormat>plain</reportFormat>
<forkCount>1</forkCount>
<reuseForks>false</reuseForks>
<!-- 关键:给 JVM 加 -Dfile.encoding=UTF-8,避免 ??? 乱码 -->
<argLine>
-Dfile.encoding=UTF-8
-javaagent:"${settings.localRepository}/org/aspectj/aspectjweaver/${aspectj.version}/aspectjweaver-${aspectj.version}.jar"
</argLine>
<systemPropertyVariables>
<allure.results.directory>${allure.results.directory}</allure.results.directory>
</systemPropertyVariables>
</configuration>
</plugin>
</plugins>
</build>
2. AbstractCaseTest - 通用执行流程中调用Allure的API将report中显示名设置成yaml中case属性的值
java
public abstract class AbstractCaseTest extends ApiBase {
/** 通用执行流程 */
@SuppressWarnings("unchecked")
protected void execute(Map<String, Object> caseData) {
String caseName = (String) caseData.get("case");
String method = (String) caseData.get("method");
// 把 YAML 里的 case 名设成报告里的显示名
Allure.getLifecycle().updateTestCase(testResult ->
testResult.setName(caseName)
);
}
}
3. ResponseAsserter
@Step是 Allure 注解,运行时由 AspectJ 织入拦截。- 方法被调用时,Allure 会在报告里生成一个"步骤"节点,名字里的
{path}、{expectedValue}会被参数值替换。 - 前提 :JVM 挂了
aspectjweaverjavaagent(surefire 里那行),否则@Step不生效。
java
@Step("校验 {path} 非空")
public static void assertNotNull(Response resp, String path) {
}
@Step("校验 {path} = {expectedValue}")
public static void assertEquals(Response resp, String path, Object expectedValue){
}
4. AllureReportListener - suite 结束时调 allure.bat 生成时间戳文件夹+ /index.html 报告
java
package engine;
import org.testng.ISuite;
import org.testng.ISuiteListener;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
public class AllureReportListener implements ISuiteListener {
// ⚠️ 改成你自己机器上的 allure.bat 绝对路径
private static final String ALLURE_CMD =
"D:\\Tools\\allure-2.29.0\\bin\\allure.bat";
@Override
public void onFinish(ISuite suite) {
System.out.println("===== AllureReportListener.onFinish 触发了 =====");
Path resultsDir = Path.of("target", "allure-results");
System.out.println("resultsDir = " + resultsDir.toAbsolutePath());
System.out.println("exists = " + Files.exists(resultsDir));
if (!Files.exists(resultsDir)) {
System.out.println("[Allure] results 目录不存在,跳过报告生成");
return;
}
String ts = LocalDateTime.now()
.format(DateTimeFormatter.ofPattern("yyyyMMdd_HHmmss"));
Path reportDir = Path.of("report", ts);
try {
ProcessBuilder pb = new ProcessBuilder(
ALLURE_CMD,
"generate", resultsDir.toString(),
"--single-file",
"--clean", "-o", reportDir.toString());
pb.redirectErrorStream(true);
pb.inheritIO();
Process p = pb.start();
int code = p.waitFor();
if (code == 0) {
System.out.println("[Allure] 报告已生成: " + reportDir.toAbsolutePath());
} else {
System.out.println("[Allure] 生成失败,exit code = " + code);
}
} catch (IOException | InterruptedException e) {
System.out.println("[Allure] 调用 allure 命令失败:");
e.printStackTrace();
}
}
}
5. testng.xml ------ 注册 Listener
xml
<listeners>
<listener class-name="engine.AllureReportListener"/>
</listeners>
6. 设置运行配置
新加一个Maven运行配置,运行命令写上clean verify,工作目录选择项目根目录,后续用这个配置跑。
三、生成的report如下


四、遇到的问题及解决办法
1. 报告里出现三个模块
问题:只跑 product,报告里却出现 admin、brand、order 三个模块。
原因 :target/allure-results 是累积目录,之前跑过的旧结果没清,Allure 读整个目录时把旧结果一起读进去了。
改动 :跑测试时加 clean,让 clean 阶段清掉 target,从而清掉 target/allure-results。
powershell
mvn clean verify
并把 maven-clean-plugin 的 filesets 扩展,显式清理结果目录和报告目录:
xml
xml
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-clean-plugin</artifactId>
<version>${maven.clean.plugin.version}</version>
<configuration>
<filesets>
<fileset>
<directory>${allure.results.directory}</directory>
</fileset>
<fileset>
<directory>${allure.report.directory}</directory>
</fileset>
</filesets>
</configuration>
</plugin>
2. 报告中文乱码 ???
问题 :报告里中文显示成 ???。
原因:跑测试的 JVM 默认编码不是 UTF-8(Windows 中文系统常见 GBK)。
改动 :Surefire 的 argLine 加 -Dfile.encoding=UTF-8:
xml
bash
<argLine>
-Dfile.encoding=UTF-8
-javaagent:"${settings.localRepository}/org/aspectj/aspectjweaver/${aspectj.version}/aspectjweaver-${aspectj.version}.jar"
</argLine>
3. Corrupted channel by directly writing to native stream
现象 :构建输出里出现这个警告,附带 dumpstream 文件。
原因 :allure-maven 插件打印「Report successfully generated to ...」时,直接写原生 stdout,绕过了 Surefire 的日志通道,Surefire 记录警告。
结论 :这是警告,不是错误,报告已成功生成。可以忽略。
4. allure添加到了系统变量后IDEA终端找不到
现象 :下载了allure并且添加到了系统变量Path中,在IDEA中打开终端却找不到allure。
原因 :IDEA 的终端用的是 IDEA 启动时复制的环境变量快照,不会实时读后来改的系统 PATH。
结论 :改了项目相关的环境变量,要重启IDEA。(把所有IDEA页面关闭再重新打开,不能只关你要跑的项目窗口)