1. 概述

在使用 Selenium 编写自动化测试时,我们经常需要对网页或页面的某一部分进行截图。这在调试测试失败验证应用在不同浏览器中行为一致性时非常有用。

本文将介绍几种在 JUnit 测试中通过 Selenium WebDriver 实现截图的方法。✅
如果你对 Selenium 测试还不熟悉,可以先阅读我们的 Selenium 使用指南

2. 依赖与配置

首先,在 pom.xml 中添加 Selenium 依赖:

<dependency>
    <groupId>org.seleniumhq.selenium</groupId>
    <artifactId>selenium-java</artifactId>
    <version>3.141.59</version>
</dependency>

最新版本可从 Maven Central 获取。同时,Chrome Driver 的最新版本可以从其官网下载。

接下来,在单元测试中配置 ChromeDriver:

private static ChromeDriver driver;

@BeforeClass
public static void setUp() {
    System.setProperty("webdriver.chrome.driver", resolveResourcePath("chromedriver.mac"));

    Capabilities capabilities = DesiredCapabilities.chrome();
    driver = new ChromeDriver(capabilities);
    driver.manage()
      .timeouts()
      .implicitlyWait(5, TimeUnit.SECONDS);

    driver.get("http://www.google.com/");
}

这是一个标准的 ChromeDriver 配置,用于控制本地 Chrome 浏览器。我们设置了 5 秒的隐式等待时间,避免元素未加载完成就操作导致异常。⚠️

最后,在测试执行前打开 Google 首页作为操作目标。

3. 截取可视区域

Selenium 提供了 TakesScreenshot 接口,可以直接用于截取当前浏览器窗口的可视区域。

我们封装一个简单的截图方法:

public void takeScreenshot(String pathname) throws IOException {
    File src = ((TakesScreenshot) driver).getScreenshotAs(OutputType.FILE);
    FileUtils.copyFile(src, new File(pathname));
}

关键点如下:

  • ✅ 将 driver 强转为 TakesScreenshot 接口
  • ✅ 调用 getScreenshotAs(OutputType.FILE) 获取截图文件对象
  • ✅ 使用 Apache Commons IO 的 FileUtils.copyFile 保存到指定路径

整个过程仅需两行核心代码,简单粗暴有效。💥

在测试中调用该方法:

@Test
public void whenGoogleIsLoaded_thenCaptureScreenshot() throws IOException {
    takeScreenshot(resolveTestResourcePath("google-home.png"));

    assertTrue(new File(resolveTestResourcePath("google-home.png")).exists());
}

截图保存至 test/resources/google-home.png,并通过断言验证文件是否存在。

4. 截取页面特定元素

有时候我们只关心某个元素(比如登录按钮、弹窗、Logo),而不是整个页面。Selenium 原生 API 不支持直接截取元素,但我们可以借助第三方库 aShot 实现。

aShot 从 Selenium 3 开始被广泛使用,提供了更灵活的截图能力。

先添加依赖:

<dependency>
    <groupId>ru.yandex.qatools.ashot</groupId>
    <artifactId>ashot</artifactId>
    <version>1.5.4</version>
</dependency>

aShot 提供了流畅的 API(Fluent API),可灵活配置截图策略。

下面示例展示如何截取 Google 首页的 Logo:

@Test
public void whenGoogleIsLoaded_thenCaptureLogo() throws IOException {
    WebElement logo = driver.findElement(By.id("hplogo"));

    Screenshot screenshot = new AShot().shootingStrategy(ShootingStrategies.viewportPasting(1000))
      .coordsProvider(new WebDriverCoordsProvider())
      .takeScreenshot(driver, logo);

    ImageIO.write(screenshot.getImage(), "jpg", new File(resolveTestResourcePath("google-logo.png")));
    assertTrue(new File(resolveTestResourcePath("google-logo.png")).exists());
}

关键步骤解析:

  1. ✅ 使用 findElement(By.id("hplogo")) 定位目标元素
  2. ✅ 设置截图策略:viewportPasting(1000) 表示滚动视口并拼接截图,最长等待 1000ms
  3. ✅ 设置坐标提供器:WebDriverCoordsProvider 使用 WebDriver 原生 API 获取元素坐标,避免 jQuery 兼容性问题 ❌
    • ⚠️ 默认使用 jQuery 解析坐标,但某些 WebDriver(如 HtmlUnit)不支持 JS,容易踩坑
  4. ✅ 调用 takeScreenshot(driver, logo) 截取指定元素
  5. ✅ 使用 ImageIO.writeScreenshot.getImage() 写入文件

aShot 会自动计算元素位置和尺寸,并从全屏截图中裁剪出目标区域,结果精准可靠。

5. 总结

本文介绍了两种 Selenium 截图方案:

方式 工具 适用场景
原生 API TakesScreenshot 截取整个可视区域,简单直接
第三方库 aShot 截取特定元素、处理滚动、跨浏览器一致性

✅ 推荐在复杂项目中使用 aShot,主要原因:

  • 抽象了不同 WebDriver 的截图差异(如 Chrome、Firefox 渲染行为不同)
  • 支持元素级截图、滚动拼接、高亮区域等高级功能
  • API 设计清晰,易于集成

完整示例代码已托管至 GitHub:https://github.com/eugenp/tutorials/tree/master/testing-modules/selenium

如果你在 CI/CD 中做自动化视觉回归测试,aShot + Image Comparison 是个不错的组合,后续可以单独写一篇展开。


原始标题:Taking Screenshots With Selenium WebDriver