在 @Lily 的 Juint4 + WebDriver 入门篇 中, Lily 问起了 HtmlUnit Driver。对 HtmlUnit Driver 我倒是没有接触太多, 所以特意去找了些文章看看。
在 selenium 官方 wiki 上说:
This is currently the fastest and most lightweight implementation of WebDriver. As the name suggests, this is based on HtmlUnit.
所以想要了解 HtmlUnit Driver, 就必先追根溯源地研究下 HtmlUnit。
HtmlUnit is a “GUI-Less browser for Java programs”. It models HTML documents and provides an API that allows you to invoke pages, fill out forms, click links, etc… just like you do in your “normal” browser.
简单来说, HtmlUnit 就是没有界面的,你看不见的,但是却能做浏览器的活的 JAVA 版本的浏览器。需要说明的是,HtmlUnit 本身不是一个测试框架, 它真的只是一个模拟浏览器行为的程序。 所以需要和 Junit 或者 TestNG 等测试框架配合起来使用。同时,很多开源的工具也使用 HtmlUnit 来模拟浏览器行为,比如大名鼎鼎的 WebDriver。
下面,搬抄一把 HtmlUnit 的入门指南:
建立项目 使用 maven 创建一个 htmlunit 的试用项目
mvn archetype:generate -DgroupId=com.testchina -DartifactId=my-htmlunit-test -DinteractiveMode=false
(不得不夸下 Maven, 构建的好工具啊。)
修改 pom.xml, 加入 HtmlUnit 依赖, 升级 Junit 为4.10。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
<project xmlns ="http://maven.apache.org/POM/4.0.0" xmlns:xsi ="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation ="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" >
<modelVersion > 4.0.0</modelVersion >
<groupId > com.testchina</groupId >
<artifactId > my-htmlunit-test</artifactId >
<version > 1.0-SNAPSHOT</version >
<packaging > jar</packaging >
<name > my-htmlunit-test</name >
<url > http://maven.apache.org</url >
<properties >
<project.build.sourceEncoding > UTF-8</project.build.sourceEncoding >
</properties >
<dependencies >
<dependency >
<groupId > junit</groupId >
<artifactId > junit</artifactId >
<version > 4.10</version >
<scope > test</scope >
</dependency >
<dependency >
<groupId > net.sourceforge.htmlunit</groupId >
<artifactId > htmlunit</artifactId >
<version > 2.10</version >
</dependency >
</dependencies >
</project >
然后,执行:
mvn install
mvn eclipse:eclipse
之后, 就可以在 eclipse 里导入项目。接着,我们来写第一个例子。
试用 第一个例子:
a. 访问 http://htmlunit.sourceforge.net
b. 验证网页的 titile
c. 验证网页内容
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
package com.testchina;
import static org.junit.Assert.*;
import org.junit.Test;
import com.gargoylesoftware.htmlunit.WebClient;
import com.gargoylesoftware.htmlunit.html.HtmlPage;
public class MyHtmlUnitTest {
@Test
public void homePage () throws Exception {
final WebClient webClient = new WebClient();
final HtmlPage page = webClient.getPage("http://htmlunit.sourceforge.net" );
assertEquals("HtmlUnit - Welcome to HtmlUnit" , page.getTitleText());
final String pageAsXml = page.asXml();
assertTrue(pageAsXml.contains("<body class=\"composite\">" ));
final String pageAsText = page.asText();
assertTrue(pageAsText.contains("Support for the HTTP and HTTPS protocols" ));
webClient.closeAllWindows();
}
}
第二个例子: 指定浏览器
1
2
3
4
5
6
7
8
9
@Test
public void homePage_Firefox () throws Exception {
final WebClient webClient = new WebClient(BrowserVersion.FIREFOX_10);
final HtmlPage page = webClient
.getPage("http://htmlunit.sourceforge.net" );
assertEquals("HtmlUnit - Welcome to HtmlUnit" , page.getTitleText());
webClient.closeAllWindows();
}
很简单,在初始化 WebClient 的时候,传入浏览器版本, 目前 2.10 里面支持:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
static {
INTERNET_EXPLORER_6.initDefaultFeatures();
INTERNET_EXPLORER_7.initDefaultFeatures();
INTERNET_EXPLORER_8.initDefaultFeatures();
FIREFOX_3.initDefaultFeatures();
FIREFOX_3_6.initDefaultFeatures();
FIREFOX_10.initDefaultFeatures();
final PluginConfiguration flash = new PluginConfiguration("Shockwave Flash" ,
"Shockwave Flash 9.0 r31" , "libflashplayer.so" );
flash.getMimeTypes().add(new PluginConfiguration.MimeType("application/x-shockwave-flash" ,
"Shockwave Flash" , "swf" ));
FIREFOX_3.getPlugins().add(flash);
FIREFOX_3_6.getPlugins().add(flash);
FIREFOX_10.getPlugins().add(flash);
CHROME_16.initDefaultFeatures();
CHROME_16.setApplicationCodeName("Mozilla" );
CHROME_16.setPlatform("MacIntel" );
CHROME_16.setCpuClass(null );
CHROME_16.setBrowserLanguage("undefined" );
}
第三个例子: 获取页面元素
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
@Test
public void getElements () throws Exception {
final WebClient webClient = new WebClient();
final HtmlPage page = webClient.getPage("http://htmlunit.sourceforge.net" );
final List<?> divs = page.getByXPath("//div" );
System.out.println(((HtmlDivision)divs.get(0 )).asText());
final List<HtmlAnchor> anchors = page.getAnchors();
for (HtmlAnchor anchor : anchors) {
System.out.println(anchor.getAttribute("name" ));
}
webClient.closeAllWindows();
}
第四个例子: 提交表单
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
@Test
public void submittingForm () throws Exception {
final WebClient webClient = new WebClient();
final HtmlPage page1 = webClient.getPage("http://some_url" );
final HtmlForm form = page1.getFormByName("myform" );
final HtmlSubmitInput button = form.getInputByName("submitbutton" );
final HtmlTextInput textField = form.getInputByName("userid" );
textField.setValueAttribute("root" );
final HtmlPage page2 = button.click();
webClient.closeAllWindows();
}
是不是很棒? 所有浏览器能做的,它都能做,我们再来看下它的特性:
支持 HTTP and HTTPS 协议
支持 cookies
支持 Post, Get, Head, Delete
支持代理
能分析 HTTP responses
能自定义 HTTP request head
支持 Javascript
于是有第五个例子: 使用 javascript
这里的 Javascript 的意思,是指 HtmlUnit 可以通过 js 引擎执行 javascript 代码。
HtmlUnit provides excellent JavaScript support, simulating the behavior of the configured browser (Firefox or Internet Explorer). It uses the Rhino JavaScript engine for the core language (plus workarounds for some Rhino bugs) and provides the implementation for the objects specific to execution in a browser.
比如我们的页面有一个 alert 事件:
1
2
3
<html > <head > <title > Alert sample</title > </head >
<body onload ='alert("foo");' >
</body > </html >
我们如何捕捉它呢?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
@Test
public void alerts () throws Exception {
final WebClient webClient = new WebClient();
final List collectedAlerts = new ArrayList();
webClient.setAlertHandler(new CollectingAlertHandler(collectedAlerts));
webClient.getPage("http://tciludev01/test.html" );
final List expectedAlerts = Collections.singletonList("foo" );
assertEquals(expectedAlerts, collectedAlerts);
}
是不是很轻巧? 像真正的浏览器一样, HtmlUnit 可以响应各种 Javascript 事件, 执行各种 Javascript 代码。
对于 HtmlUnit, 我就初略看了看, 总的印象是轻,不用启动笨重的浏览器就能做到和浏览器一样的行为, 和 Junit4 很好的搭配,可以 写出轻巧优美的测试案例, 同时也能为测试省去不少时间。这在前期测试驱动开发的时候,特别是 Web 应用开发,可以节省去不少时间。
参见:
http://htmlunit.sourceforge.net/
http://maven.apache.org/guides/getting-started/maven-in-five-minutes.html
http://code.google.com/p/selenium/wiki/HtmlUnitDriver
http://htmlunit.sourceforge.net/javascript-howto.html