Web功能性测试
在日常工作中,我们时常需要对网站进行功能性测试,测试网站的某些功能是否正常。简单的测试如网页是否进行了gzip压缩,网页编码是否正确,网页载入时间是否正常,网页缓存时间是否正常等。复杂一点的包括网页截图,网页在载入的时候是否弹出了alert对话框,是否有页面错位或者javascript错误,网页载入的资源是否是304或者200的响应等。更麻烦一点的是交互式的调试,调试页面上到底是哪段javascript/CSS代码导致了错误等。
简单的Web测试
对于简单的Web测试,例如只用查看HTTP响应头部与页面内容的,只需要一个爬虫抓取网页,同时对头部和内容进行分析即可。在Linux下可以使用wget和curl(它们也都有相应的Windows版本),如下:
1
2
3
4
5
6
7
8
|
#将blog.raphaelzhang.com的页面保存到rz.html里面去
curl http://blog.raphaelzhang.com > rz.html
#只查看blog.raphaelzhang.com的HTTP头部信息
curl http://blog.raphaelzhang.com -I
#浏览blog.raphaelzhang.com时带上user-agent,referer和自定义头部
curl http://blog.raphaelzhang.com -A useragent -e http://abc.com -H "Raphael:Yes"
|
使用wget和curl可以下载网页,查看HTTP头部信息,与awk和grep之类的工具使用,一般情况下都够了。不过如果涉及到HTML的DOM解析之类的工作,就力不从心了。在这个时候,你可以使用喜欢的语言来开发自己的小工具,例如Python。如果是这样的话,你可以先看看相关的注意事项。不过,你也可以使用现成的工具,例如httpie。这是一个用Python编写的类似curl的小软件,但是它打印出来的信息可读性更好,而且还有语法高亮。如果你喜欢用WSH + javascript来写,就需要用到XmlHttpRequest组件了,其用法和普通的ajax代码一样简单。
如果你不喜欢命令行程序,更喜欢交互式的图形界面的话,各个浏览器在工具菜单下也都有相应的开发人员调试工具。第三方的工具还包括Fiddler,IETester,Firebug,以及YSlow等。
其中Fiddler最为强大,可以通过代理的方式调试所有浏览器的HTTP行为,包括查看时间-流量图,本地修改javascript/CSS代码进行交互式调试等。而IETester可以同时测试IE5.5 ~ IE10的各个IE版本,保证网页在各版本的IE下都显示正常。Firebug是火狐浏览器的一个插件,拥有极多的调试功能,查看DOM树,查看时间-流量图,调试javascript等。YSlow是Yahoo做的一个浏览器插件,支持火狐,Chrome等浏览器,它能对你的网页进行检查,并为你的网页打分,并提出建议,以改善网页的性能,这些建议包括对网页进行gzip,将javascript放到尾部等。
PhantomJS测试
虽然一些简单的测试可以通过爬虫的方式来做,但是如果涉及到比较复杂的javascript代码和CSS渲染的话,就必须使用真正的浏览器了。毕竟自己实现DOM解析还相对容易,但是如果要做javascript虚拟机和渲染的话,工作量就太大了。
PhantomJS是一个无界面浏览器(Headless Browser),可以在后台运行,通过javascript代码控制,你可以用它来做网站测试(包括自动登录,表单提交等),页面截屏和流量监控。PhantomJS使用的是Webkit作为内核,能运行网页里的javascript代码和解析CSS/HTML以渲染页面,因此相当强大。在PhantomJS的examples目录中有很多例子可以学习,例如生成HAR流量图的netsniff.js等。下面是一个生成网站截图的例子:
1
2
3
4
5
6
7
8
9
10
11
12
|
varpage=newWebPage();
page.open(encodeURI("http://blog.raphaelzhang.com"),function(status){
if(status!=='success'){
console.log('Unable to load page!');
}else{
window.setTimeout(function(){
page.render('snapshot.png');
phantom.exit();
},200);
}
});
|
顺便说一句,如果需要将查看HAR流量图自动化嵌入自己网站的,网上也有开源的程序可以使用。下面是用PhantomJS做出来的流量统计数据直接得到的HAR图。
不过PhantomJS虽好,也有几个问题:
- 不支持对IE浏览器特定特性的测试,毕竟PhantomJS是基于WebKit的,因此对于特定于IE的bug是无法检查出来的
- 不支持对弹窗的检测,就是无法检测网页对
window.open
的调用,,也无法有效地截获新窗口的创建和弹出 - 无法检测网页上的javascript错误
如果要解决上述问题,就需要自己做一个基于IE(Trident)的无界面浏览器了,网上可以参考的代码是CodeProject的这篇文章和SourceForge上的开源项目IECapt。
WSH javascript测试
由于我们网站90%以上的用户用的都是IE,而有一些代码也是特定于IE的,因此在测试的时候,必须要对IE进行自动化测试。
在Windows下进行自动化测试,自然要使用我最熟悉的WSH+javascript了,可以使用WScript对象和众多ActiveX组件来完成诸多功能,而且语法和普通javascript都一样,主要需要熟悉的就是各个组件的接口。
使用javascript进行IE测试的流程是:
- 通过
WScript.createObject
创建一个IE对象,并绑定它的事件回调(Event Callback/Sink) - 调用IE对象的
navigate2
方法,打开指定的网页,并将其Visible
属性设置为true - 在IE对象的
OnDocumentComplete
事件中,检查网页是否已经完全载入(不然无法访问到document对象) - 通过document对象访问各个HTML对象以及其计算出来的CSS属性,并模拟用户输入进行功能性测试
- 在最后调用IE对象的
quit
方法关闭IE,如果为了保险,可以找到所有的IE窗口,向其发送Alt+F4按键将其关闭 - 将得到的测试信息通过手机短信(如定制的HTTP接口)或者电子邮件(通过CDO.Message对象)发送到对应人员
上面是大致的流程,具体在开发过程中,还会遇到一些其他的问题:
- 在javascript中如何创建与绑定事件回调
- 如何在测试中绕过IE的阻止自动弹窗的设置,使得可以进行用户模拟点击打开新窗口的测试(不然弹窗会被阻止)
先说第一个问题。其实在创建一个ActiveX组件的时候,WScript.createObject方法第一个参数是组件名,第二个参数就是事件回调函数的前缀了。例如对于IE对象来说,它的组件名是InternetExplorer.Application,对应的事件有DocumentComplete、OnQuit等(参见DWebBrowserEvents2),假设我希望收到DocumentComplete事件通知,可以这样写代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
varshouldQuit=false;
function_eventsDocumentComplete(obj,url){
WScript.Echo(url);
}
function_eventsOnQuit(){
shouldQuit=true;
}
varbrowser=WScript.createObject("InternetExplorer.Application","_events");
browser.navigate2("http://blog.raphaelzhang.com");
browser.visible=true;
while(!shouldQuit)
{
WScript.sleep(100);
}
|
在上面的代码中需要加入一个while循环,这样才能不退出程序,继而收到事件响应。
在HTML文档都已经载入完毕以后,就可以访问browser的document对象获取DOM树,进行一系列操作和测试了,例如通过document.getElementById('btnSumbit').click()
模拟表单提交之类的。
另外,在IE中,如果通过代码模拟点击想产生一个新窗口,往往会被IE自动弹窗阻拦功能挡住,就是平时常见的顶部提示阻止了一个弹窗的细黄条。在测试过程中,我们往往需要模拟用户输入产生自动弹窗,这时候,需要在测试的时候去掉这个功能,然后在测试结束的时候再打开这个设置。要做到这一点,只需要修改注册表的HKEY_CURRENT_USER下的\Software\Microsoft\Internet Explorer\New Windows\Allow项,添加上对应的域名即可。在javascript里可以这样写:
1
2
3
4
5
6
7
8
9
10
|
//对host这个域名允许自动弹窗
varshell=WScript.CreateObject("WScript.Shell");
varregKey="HKCU\\Software\\Microsoft\\Internet Explorer\\New Windows\\Allow\\" + host;
shell.RegWrite(regKey, 0, "REG_BINARY");
//测试代码
//...
//恢复自动弹窗阻止
shell.RegDelete(regKey);
|
另外,进行IE测试需要打开Windows桌面才行,因此它有一个比较郁闷的要求,就是不能是未登录状态。为了解决这个问题,我们开了一个Windows虚拟机,在虚拟机里面专门设置了计划任务运行这个代码。
更多WSH + javascript开发的事情,可以参见这篇文章。在这里有一个比较完整的WSH + javascript测试的例子,包括单元测试模板,测试页面链接,测试弹窗与模拟提交,测试结束后发送报警电子邮件等。
交互性调试
上面说的都是自动化测试,有的时候我们也需要进行交互式的调试,例如当页面出现了javascript或者CSS错误的时候。毕竟,每次为了调试都把代码放到vcs中,再通过cms发布出来看效果,不仅速度慢,而且也会在代码版本中带来无数的垃圾。
在上面我们已经提过,各个浏览器在工具菜单下也都有相应的开发人员调试工具,我们可以在相应的控制台下修改CSS和执行javascript代码。在javascript代码里,你可以访问和修改当前页面的所有变量和函数,例如将某个DOM元素的onclick事件修改成你希望的样子来调试,等等。如果javascript代码非常简单,也可以直接在浏览器的地址栏里输入javascript:window.alert(document.title);
,以弹框显示出当前页面的标题。
不过对于iframe中需要访问top窗口的javascript代码,还有那些在页面载入和初始化时运行的代码,上面的方法就不适用了。在这个时候,我们需要使用Fiddler,让它在读取相应文件的时候就载入我们修改过的文件。Fiddler的使用方法可以参见这里,这里也有一篇类似的文章。