项目使用的jar版本为:allure-junit:4.2.28,junit4.12
在BeforeClass注解中执行报错的测试类,在统计Allure报告时不会被统计进去,也不会在报告中有体现,会丢失一部分的测试结果,需要找到方法将BeforeClass报错的类也添加进入Allure报告。
通过谷歌,发现Allure-Java关闭了一个类似的bug,标记为了Closed as not planned,并不支持在Junit4版本通过配置实现。
最终解决办法如下:
使用方法:@RunWith(FilterMethodsRunner.class)
import org.junit.runners.BlockJUnit4ClassRunner
import org.junit.runners.model.Statement
class FilterMethodsRunner extends BlockJUnit4ClassRunner{
@Override
protected Statement withBeforeClasses(Statement statement) {
// 包装原始的 BeforeClass 逻辑
Statement originalStatement = super.withBeforeClasses(statement)
return new Statement() {
@Override
void evaluate() throws Throwable {
try {
originalStatement.evaluate()
} catch (Throwable t) {
// 捕获 BeforeClass 的异常
try {
byte[] screenshot = new byte[0]
try {
// 如果没有截图方法,注释相关内容
screenshot = TestPage.takeScreenShot()
} catch (Exception ignored){}
AllureExtension.logBeforeClassFailure(
getTestClass().getName(),
t,
screenshot
)
} catch (Exception e) {
e.printStackTrace()
}
throw t // 重新抛出异常
}
}
}
}
}
:
import io.qameta.allure.Allure
import io.qameta.allure.AllureLifecycle
import io.qameta.allure.model.*
import io.qameta.allure.util.ResultsUtils
import java.util.function.Consumer
class AllureExtension {
/**
* 记录 BeforeClass 方法失败
* 如果没有 screenshot相关信息请注释删除相关代码
*/
static void logBeforeClassFailure(String className, Throwable throwable, byte[] screenshot) {
// 获取 Allure 生命周期实例
AllureLifecycle lifecycle = Allure.getLifecycle()
// 创建测试结果UUID
String uuid = UUID.randomUUID().toString()
// 创建测试结果
TestResult result = new TestResult()
.setName("执行BeforeClass报错:${className}")
.setFullName("执行BeforeClass报错:${className}")
.setUuid(uuid)
.setStatus(Status.FAILED)
.setStatusDetails(ResultsUtils.getStatusDetails(throwable).get())
.setStart(System.currentTimeMillis())
.setStop(System.currentTimeMillis() + 1)
// 添加标签
result.getLabels().add(new Label()
.setName("package")
.setValue(className))
result.getLabels().add(new Label()
.setName("testClass")
.setValue(className))
result.getLabels().add(new Label()
.setName("testMethod")
.setValue("beforeClass"))
result.getLabels().add(new Label()
.setName("suite")
.setValue("执行BeforeClass报错:${className}"))
result.getLabels().add(new Label()
.setName("host")
.setValue(getHostName()))
result.getLabels().add(new Label()
.setName("thread")
.setValue("${Thread.currentThread().id}"))
result.getLabels().add(new Label()
.setName("framework")
.setValue("junit4"))
result.getLabels().add(new Label()
.setName("language")
.setValue("java"))
// 开始记录测试结果
lifecycle.scheduleTestCase(result)
lifecycle.startTestCase(uuid)
// 添加步骤信息
String stepUuid = UUID.randomUUID().toString()
StepResult stepResult = new StepResult()
.setName("执行BeforeClass报错:${className}")
.setStatus(Status.FAILED)
.setStatusDetails(ResultsUtils.getStatusDetails(throwable).get())
.setStart(System.currentTimeMillis())
.setStop(System.currentTimeMillis() + 500)
// 添加截图附件
lifecycle.startStep(uuid, stepUuid, stepResult)
if (screenshot && screenshot.length > 0) {
lifecycle.addAttachment("报错时页面截图", "image/png", "png", new ByteArrayInputStream(screenshot))
}
// 结束步骤和测试
lifecycle.stopStep(stepUuid)
lifecycle.updateTestCase(uuid, new Consumer<TestResult>() {
@Override
void accept(TestResult testResult) {
testResult.setStatus(Status.FAILED)
}
})
lifecycle.stopTestCase(uuid)
lifecycle.writeTestCase(uuid)
}
private static String getHostName() {
try {
return InetAddress.localHost.hostName
} catch (Exception e) {
return "unknown"
}
}
}