2. 关于 HtmlUnit
HtmlUnit 是一款无界面的浏览器——专为程序化操作设计,而非直接供用户使用。
这款浏览器支持 JavaScript(通过 Mozilla Rhino 引擎),即使面对复杂 AJAX 功能的网站也能轻松应对。所有操作都能模拟 Chrome 或 Firefox 等主流 GUI 浏览器的行为。
虽然名字带"Unit",但别被误导——它不仅是测试框架,功能远超测试范畴。HtmlUnit 已被集成到 Spring 4 中,可与 Spring MVC Test 框架无缝协作。
✅ 核心特点:
- 纯 Java 实现
- 支持 JavaScript/AJAX
- 无需 GUI 环境
- 可模拟主流浏览器
3. 下载与 Maven 依赖
HtmlUnit 可通过 SourceForge 或官网 下载,也可集成到构建工具(如 Maven/Gradle)。以下是 Maven 依赖示例:
<dependency>
<groupId>net.sourceforge.htmlunit</groupId>
<artifactId>htmlunit</artifactId>
<version>2.23</version>
</dependency>
最新版本可在这里查询。
⚠️ 注意:版本号需根据实际需求更新,示例使用的是历史版本。
4. Web 测试实战
Web 应用测试方式众多,HtmlUnit 提供了一种独特方案:直接解析 HTML 页面,模拟用户交互,验证 JavaScript/CSS 语法,提交表单并解析响应——全部通过纯 Java 代码实现。
先看基础示例:创建 WebClient
访问 www.baeldung.com
首页:
private WebClient webClient;
@Before
public void init() throws Exception {
webClient = new WebClient();
}
@After
public void close() throws Exception {
webClient.close();
}
@Test
public void givenAClient_whenEnteringBaeldung_thenPageTitleIsOk()
throws Exception {
HtmlPage page = webClient.getPage("/");
Assert.assertEquals(
"Baeldung | Java, Spring and Web Development tutorials",
page.getTitleText());
}
若网站存在 JavaScript/CSS 问题,测试可能抛出警告或错误。建议优先修复这些问题。
当确认错误来自第三方库且无法修改时,可通过 setThrowExceptionOnScriptError(false)
忽略:
@Test
public void givenAClient_whenEnteringBaeldung_thenPageTitleIsCorrect()
throws Exception {
webClient.getOptions().setThrowExceptionOnScriptError(false);
HtmlPage page = webClient.getPage("/");
Assert.assertEquals(
"Baeldung | Java, Spring and Web Development tutorials",
page.getTitleText());
}
5. Web 爬虫应用
HtmlUnit 不仅限于自有网站测试——作为浏览器,它可导航至任何网页,按需收发数据。这种网页抓取(Web Scraping) 流程中,HtmlUnit 负责数据获取与解析。
以下示例演示:访问 Baeldung 文章归档页,提取最新文章标题(首个 <h1>
标签):
@Test
public void givenBaeldungArchive_whenRetrievingArticle_thenHasH1()
throws Exception {
webClient.getOptions().setCssEnabled(false);
webClient.getOptions().setJavaScriptEnabled(false);
String url = "/full_archive";
HtmlPage page = webClient.getPage(url);
String xpath = "(//ul[@class='car-monthlisting']/li)[1]/a";
HtmlAnchor latestPostLink
= (HtmlAnchor) page.getByXPath(xpath).get(0);
HtmlPage postPage = latestPostLink.click();
List<HtmlHeading1> h1
= (List<HtmlHeading1>) postPage.getByXPath("//h1");
Assert.assertTrue(h1.size() > 0);
}
关键点解析:
- 禁用 CSS/JavaScript:仅解析 HTML 结构时提升性能
- 使用 XPath 定位元素:比 ID 选择更灵活
- 提取标题数据:通过
getByXPath
获取<h1>
列表
实际爬虫可扩展提取更多数据,例如同时抓取 <h2>
标签:
Java Web Weekly, Issue 135
1. Spring and Java
2. Technical and Musings
3. Comics
4. Pick of the Week
6. AJAX 处理技巧
AJAX 功能可能引发问题:HtmlUnit 常在 AJAX 调用完成前返回页面。解决方法:
6.1 同步 AJAX 调用
webClient.setAjaxController(new NicelyResynchronizingAjaxController());
将主线程调用转为同步执行,确保测试状态稳定。
6.2 显式等待
webClient.waitForBackgroundJavaScript(1000); // 等待 1 秒
或:
webClient.waitForBackgroundJavaScriptStartingBefore(1000);
在页面加载后、操作前调用,给予 AJAX 完成时间。
6.3 条件等待
for (int i = 0; i < 20; i++) {
if (condition_to_happen_after_js_execution) {
break;
}
synchronized (page) {
page.wait(500);
}
}
轮询检查 JS 执行后的特定条件。
6.4 切换浏览器模拟
WebClient webClient = new WebClient(BrowserVersion.CHROME);
不同浏览器对 JS/AJAX 的支持度不同,切换版本可能解决兼容性问题。
⚠️ 踩坑提示:AJAX 处理是 HtmlUnit 最易出错的部分,建议组合使用上述方法。
7. Spring 集成示例
测试自有 Spring 应用时更简单——无需启动真实服务器。以下实现一个极简应用:包含表单的 HTML 页面,用户输入文本后提交,页面显示该文本。
@RunWith(SpringJUnit4ClassRunner.class)
@WebAppConfiguration
@ContextConfiguration(classes = { TestConfig.class })
public class HtmlUnitAndSpringTest {
@Autowired
private WebApplicationContext wac;
private WebClient webClient;
@Before
public void setup() {
webClient = MockMvcWebClientBuilder
.webAppContextSetup(wac).build();
}
@Test
public void givenAMessage_whenSent_thenItShows() throws Exception {
String text = "Hello world!";
HtmlPage page;
String url = "http://localhost/message/showForm";
page = webClient.getPage(url);
HtmlTextInput messageText = page.getHtmlElementById("message");
messageText.setValueAttribute(text);
HtmlForm form = page.getForms().get(0);
HtmlSubmitInput submit = form.getOneHtmlElementByAttribute(
"input", "type", "submit");
HtmlPage newPage = submit.click();
String receivedText = newPage.getHtmlElementById("received")
.getTextContent();
Assert.assertEquals(receivedText, text);
}
}
核心步骤:
- 通过
MockMvcWebClientBuilder
构建WebClient
- 访问
localhost
提供的页面 - 填写表单(ID="message")并提交
- 验证响应页面文本(ID="received")
✅ 优势:集成测试无需部署,直接在测试环境中模拟完整请求流程。
8. 总结
HtmlUnit 是强大的 Web 测试工具,能模拟浏览器行为完成表单填写、提交等操作。其核心价值在于:
- 测试场景:轻松实现 Web 应用集成测试,尤其与 Spring 4 结合后,无需服务器即可验证页面逻辑
- 爬虫场景:自动化网页数据抓取(解析/存储/分析)
- 扩展场景:任何需程序化操作浏览器的任务
完整代码可在 GitHub 获取。
❌ 局限性:复杂 JavaScript/AJAX 场景需额外配置,对动态渲染支持有限。