如何在Selenium WebDriver中将截图存为字符串并保存到Excel工作表
问题改造方案
你当前代码存在两个核心问题:
- 原本的
FailedTestScreenCapture是JUnit专属的测试规则,只会在JUnit执行用例抛出异常时自动触发截图,你当前自定义的main方法循环执行测试逻辑,完全没有走JUnit执行链,原有截图逻辑不会触发 - 你直接调用
failedTstCase.toString()拿到的只是对象内存地址,无法获取截图路径;且你初始化FailedTestScreenCapture时driver还是null,就算触发截图也会报空指针
1. 改造FailedTestScreenCapture类
将截图方法改为可主动调用,同时返回截图的存储路径,方便后续写入Excel:
package utilities; import java.io.File; import java.util.UUID; import org.openqa.selenium.io.FileHandler; import org.junit.rules.MethodRule; import org.junit.runners.model.FrameworkMethod; import org.junit.runners.model.Statement; import org.openqa.selenium.OutputType; import org.openqa.selenium.TakesScreenshot; import org.openqa.selenium.WebDriver; public class FailedTestScreenCapture implements MethodRule { private WebDriver driver; // 统一管理截图存储根路径 private static final String SCREENSHOT_DIR = "./Screenshots/"; public FailedTestScreenCapture(WebDriver driver) { this.driver = driver; // 初始化时自动创建截图目录,避免路径不存在报错 File dir = new File(SCREENSHOT_DIR); if (!dir.exists()) { dir.mkdirs(); } } // 新增:支持主动调用的截图方法,返回截图完整存储路径 public String captureScreen(String caseName) { try { TakesScreenshot ts = (TakesScreenshot) driver; File source = ts.getScreenshotAs(OutputType.FILE); String fileName = caseName + "_" + UUID.randomUUID() + ".jpg"; String fullPath = SCREENSHOT_DIR + fileName; FileHandler.copy(source, new File(fullPath)); return fullPath; } catch (Exception e) { System.out.println("截图失败:" + e.getMessage()); return ""; } } // 保留原有JUnit规则逻辑,不影响后续JUnit用例执行 @Override public Statement apply(final Statement statement, final FrameworkMethod frameworkMethod, final Object obj) { return new Statement() { @Override public void evaluate() throws Throwable { try { statement.evaluate(); } catch (Throwable t) { captureScreen(frameworkMethod.getName()); throw t; } } }; } }
2. 修正OTMGeneral类逻辑
调整两个核心点:
- 把
FailedTestScreenCapture的初始化时机延后到driver实例化之后,避免空指针 - 测试失败分支主动调用截图方法,将获取到的截图路径写入Excel
package view; import java.io.IOException; import java.time.Duration; import org.openqa.selenium.By; import org.openqa.selenium.WebDriver; import org.openqa.selenium.WebElement; import org.openqa.selenium.chrome.ChromeDriver; import utilities.ExcelUtils; import utilities.FailedTestScreenCapture; import utilities.Constants; public class OTMGeneral { static WebDriver driver; static ExcelUtils excelUtils = new ExcelUtils(); // 取消静态初始化,等driver创建后再实例化 static FailedTestScreenCapture failedTstCase; static String excelFilePath = Constants.Path_TestData + Constants.File_TestData; public static void main(String args[]) throws IOException { System.setProperty("webdriver.chrome.driver", Constants.chromeDriverPath); driver = new ChromeDriver(); // 在这里初始化截图工具,此时driver已经完成实例化 failedTstCase = new FailedTestScreenCapture(driver); driver.manage().window().maximize(); driver.navigate().to(Constants.BaseUrl); driver.manage().timeouts().implicitlyWait(Duration.ofSeconds(20)); WebElement continueBtn = driver.findElement(By.xpath("/html/body/div[1]/div/div/div[2]/button")); WebElement loginBtn = driver.findElement(By.xpath("/html/body/header/div/div/nav/div/ul/li[2]/a")); WebElement popupMsg = driver.findElement(By.xpath("/html/body/div[1]/div/div")); if (popupMsg.isDisplayed()) { continueBtn.click(); driver.manage().timeouts().implicitlyWait(Duration.ofSeconds(20)); loginBtn.click(); } else { loginBtn.click(); } WebElement email = driver.findElement(By.id("Email")); WebElement pwd = driver.findElement(By.id("Password")); WebElement signInBtn = driver.findElement(By.id("btnlogin")); excelUtils.setExcelFile(excelFilePath, "Login_Data"); for (int i = 1; i <= excelUtils.getRowCountInSheet(); i++) { if (i > 1) { driver.navigate().refresh(); driver.findElement(By.xpath("/html/body/header/div/div/nav/div/ul/li[2]/a")).click(); driver.findElement(By.id("Email")).sendKeys(excelUtils.getCellData(i, 0)); driver.findElement(By.id("Password")).sendKeys(excelUtils.getCellData(i, 1)); driver.findElement(By.id("btnlogin")).click(); } else { driver.manage().timeouts().implicitlyWait(Duration.ofSeconds(20)); email.sendKeys(excelUtils.getCellData(i, 0)); pwd.sendKeys(excelUtils.getCellData(i, 1)); signInBtn.click(); } driver.manage().timeouts().implicitlyWait(Duration.ofSeconds(20)); boolean helloCustomer = driver.findElement(By.xpath("/html/body/header/div/div/nav/div/ul/li[1]/a")) .getText().equalsIgnoreCase("Regístrate"); System.out.println(helloCustomer); if (!helloCustomer) { excelUtils.setCellValue(i, 2, "Pass", excelFilePath); System.out.println("login pass"); WebElement logout = driver.findElement(By.id("logout")); logout.click(); } else { excelUtils.setCellValue(i, 2, "Fail", excelFilePath); System.out.println("login fail"); // 主动调用截图方法,传入用例行号作为标识,拿到截图路径 String screenshotPath = failedTstCase.captureScreen("login_case_" + i); excelUtils.setCellValue(i, 3, screenshotPath, excelFilePath); } driver.manage().timeouts().implicitlyWait(Duration.ofSeconds(20)); } driver.quit(); } }
3. 可选:直接嵌入截图到Excel单元格
如果不需要存路径,要把截图直接插入到Excel单元格中,可给ExcelUtils新增插入图片的方法(基于Apache POI实现):
// 该方法加入ExcelUtils类即可 public void addScreenshotToCell(Workbook workbook, Sheet sheet, int rowNum, int colNum, String imgPath) throws IOException { if (imgPath == null || imgPath.isEmpty()) return; File imgFile = new File(imgPath); if (!imgFile.exists()) return; byte[] imgBytes = Files.readAllBytes(imgFile.toPath()); int pictureIdx = workbook.addPicture(imgBytes, Workbook.PICTURE_TYPE_JPEG); CreationHelper helper = workbook.getCreationHelper(); Drawing<?> drawing = sheet.createDrawingPatriarch(); ClientAnchor anchor = helper.createClientAnchor(); // 设置图片插入的位置 anchor.setCol1(colNum); anchor.setRow1(rowNum); // 设置图片占用单元格范围,可按需调整 anchor.setCol2(colNum + 1); anchor.setRow2(rowNum + 1); Picture pic = drawing.createPicture(anchor, pictureIdx); pic.resize(0.5); // 按比例缩放图片 }
在测试失败分支拿到截图路径后,调用上述方法即可把图片插入到指定单元格。
内容的提问来源于stack exchange,提问作者Jamil
相关产品推荐
相关产品推荐

