用户浏览器操作行为的一种记录方法
记录用户浏览器操作行为是功能自动化测试工具用于录制测试脚本的先决条件,本文将介绍如何采取一种通用的方式,实现对于浏览器端透明地记录用户操作行为,从而实现用户行为向自然语言转换的过程。
对于操作行为记录的方法主要依赖于JavaScript的两个特性,第一是通过“函数劫持”实现对已有操作函数的脚本注入,第二是通过劫持HTML元素原型链(prototype chain)上EventTarget.prototype内的各类事件相关函数进一步实现对于用户操作行为的记录。“函数劫持”已经有许多文章介绍,这里不再赘述其原理,一个典型的示例代码如下:
(function(){
var alert = window.alert;
window.alert = function(message){
alert(message);
console.log("弹出消息窗口内容为" + message);
};})();
我们<input type="button" />进行举例,实现用户点击按钮行为的方法可以总结为以下几种方式:
(1)在元素内增加onclick属性;
(2)通过对元素添加addEventListener实现click事件后的回调函数处理; (3)通过如JQuery框架实现click事件处理。 因此,我们需要综合考虑以上不同实现click事件的原理,通过劫持注入我们进行自然语言转换的脚本代码:
(1)对于onclick属性,考虑采用如下方法,脚本文件命名为shadow.core.element.js:
(function(){
var inputElements = document.querySelectorAll("input");
for(var i = 0,len = inputElements.length;i < len;i++){ if(inputElements[i].onclick !== null && inputElements[i].type === "button"){ (function(){
var value = inputElements[i].value;
var onclick = inputElements[i].onclick; inputElements[i].onclick = function(){
console.log("点击" + value + "按钮");
onclick();
};
})();
}
}})();
(2)对于addEventListener实现,考虑采用如下方法,脚本文件命名为shadow.core.js
(function(){
var addEventListener = EventTarget.prototype.addEventListener;
EventTarget.prototype.addEventListener = function(type, listener, useCapture){ var id = this.id,
value = this.value,
input = this.type; if(input == "button"){
input = "按钮";
}
if(type == "click"){
(function(){
var method = listener;
listener = function(){
console.log("点击" + value + input);
method();
};
})();
}
addEventListener.call(this, type, listener, useCapture);
}; })();
(3)对于框架实现,通常是利用封装addEventListener进行实现的,因此在上述代码的基础上,需要进一步对各类框架进行判断区分对待,如JQuery框架,一般是通过$("input[type=button]".click(function(){});来进行实现的,一旦判断使用的是JQuery框架,可以在上述代码基础上,加入如下方法:
if(type == "click"){
(function(){
var method;
if($(this).click.arguments == null){//判断是否通过JQuery框架实现click
method = listener;
} else {
method = $(this).click.arguments[0];
}
listener = function(){
console.log("点击" + value + input);
method();
};
})();
}下面我们就可以将两个脚本文件引入到一个测试HTML页面中,注意两个脚本文件的引入时机,shadow.core.element.js需要在所有HTML元素渲染后引入,shadow.core.js则需要优先进行引入,测试页代码如下:<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title></title>
<script type="text/javascript" src="jquery-1.11.1.min.js"></script>
<script type="text/javascript" src="shadow.core.js"></script>
</head>
<body>
<input type="button" id="btn1" value="提交" onclick="clickHandle1()"/>
<input type="button" id="btn2" value="取消" onclick="clickHandle2()"/>
<input type="button" id="btn3" value="登录" />
<input type="button" id="btn4" value="退出" />
<input type="button" id="btn5" value="jQuery" />
<script type="text/javascript">var btn3 = document.getElementById("btn3");
btn3.addEventListener("click",clickHandle3,false);var btn4 = document.getElementById("btn4");
btn4.addEventListener("click",clickHandle4,false);function clickHandle1(){
alert("Submit!");
}function clickHandle2(){
alert("Quit!");
}function clickHandle3(){
alert("Login!");
}function clickHandle4(){
alert("Logout!");
}
$(document).ready(function(){
$("#btn5").click(function(){
alert("jQuery");
});
});
</script>
</body><script type="text/javascript" src="shadow.core.element.js"></script>
</html>
接下来,我们可以打开控制台依次点击按钮,查看效果:
按我们的意图可以实现对点击按钮用户操作行为的记录,并转换为自然语言通过控制台输出了,最后需要解决的问题是如何透明地将我们的两个JavaScript脚本注入到所访问的HTML网页内,使用非透明代理方式附加额外的服务,代理将从Web服务器接收到的完整HTML通过Jsoup解析后进行修改,之后再将注入脚本资源请求的HTML发送给浏览器,考虑如下方法:
Document doc = Jsoup.parse(html); doc.select("head").get(0).append(""); doc.select("body").get(0).append("");
好了,到此我们基本上把实现思路捋顺了,接下来的工作就是按此思路将用户操作行为进行归纳总结,再进行增强实现。此类思路的最大优点在于对于浏览器是透明,记录过程依赖天然的JavaScript脚本,而无需为浏览器安装任何插件。进一步可以将用户操作行为通过脚本化方法利用Ajax发送的后台处理引擎,测试时,通过代理将脚本再注入到HTML网页内,实现自动化测试,当然,这只是一个方向,在今后的文章中,我将进一步介绍如何实现一个纯粹的JavaScript脚本来模拟用户操作行为,以及如何管理、修改这些脚本,进而打通整个基于浏览器的功能自动化测试。