前端自动化的单元测试JsTestDriver+Jasmine.docx
《前端自动化的单元测试JsTestDriver+Jasmine.docx》由会员分享,可在线阅读,更多相关《前端自动化的单元测试JsTestDriver+Jasmine.docx(22页珍藏版)》请在冰豆网上搜索。
前端自动化的单元测试JsTestDriver+Jasmine
自动化的单元测试
采用Jasmine进行单元测试有个问题就是需要一个html来加载源代码和测试代码,测试的时候在浏览器中手动的打开这个html。
下图中是test.html。
那如果有10个test.html,需要在5种浏览器中进行测试,那就必须打开50次。
这个工作量还是很大的。
那如何可以做到有脚本去进行自动化的单元测试呢?
JsTestDriver可以做到。
JsTestDriver档案
∙用途:
javascript单元测试框架
∙下载:
∙使用文档:
JsTestDriver是一个JavaScript单元测试工具,易于与持续构建系统相集成并能够在多个浏览器上运行测试轻松实现TDD风格的开发。
当在项目中配置好js-test-driver以后,如同junit测试java文件一般,js-test-driver可以直接通过直接运行js文件,来对js文件单元测试。
下图是JsTestDriver的架构:
捕获不同的浏览器之后,服务器会负责将JavaScript测试用例运行程序代码加载到浏览器中。
可以通过命令行捕获浏览器,也可以通过将浏览器指向服务器URL来捕获浏览器。
一旦捕获到浏览器,该浏览器就被称为从属浏览器。
服务器可以加载JavaScript代码,在每个浏览器上执行测试用例,然后将结果返回给客户端。
客户端(命令行)需要以下两个主要项目:
JavaScript文件,即源文件和测试文件
配置文件,用于组织源文件和测试文件的加载
这个架构比较灵活,允许单个服务器从网络中的其他机器捕获任意数量的浏览器。
例如,如果您的代码在Linux上运行但您想针对另一个Windows机器上的MicrosoftInternetExplorer运行您的测试用例,那么这个架构很有用。
Jasmine+JsTestDriver
采用Jasmine编写单元测试代码,JsTestDriver作为自动化测试的平台,在多浏览器下进行自动化测试。
从简单例子开始
∙新建名为simply的工程
∙下载最新的Jasmine
copy下图文件到simply/lib下,实际上只使用到了jasmine.js
∙下载最新的JsTestDriver
将JsTestDriver-1.3.4.b.jar放到simply目录下。
∙下载Jasmine对JsTestDriver的适配器
copyJasmineAdapter.js到simply/lib目录下
∙编写js源代码和单元测试代码
src/person.js代码:
∙functionPerson(name,age){
∙this.name=name;
∙this.age=age;
∙}
∙
∙Person.prototype.getName=function(){
∙returnthis.name;
∙}
∙
∙Person.prototype.getAge=function(){
∙returnthis.age;
∙}
spec/person.spec.js代码:
describe('PersonClassTest',function(){
varperson=newPerson('Colin',31);
it('shouldbeworkableforgetName',function(){
expect(person.getName()).toEqual('Colin');
});
it('shouldbeworkableforgetAge',function(){
expect(person.getAge()).toEqual(31);
});
});
∙在simply目录下建配置文件,jsTestDriver.conf内容如下:
∙server:
http:
//localhost:
9876
∙load:
∙-lib/jasmine.js
∙-lib/JasmineAdapter.js
∙-src/person.js
∙test:
∙-spec/person.spec.js
∙
∙server:
服务器路径
∙load:
依赖脚本
∙test:
测试脚本
具体的配置参数,参考官方说明
∙在simply目录下建server.bat文件,内容如下:
java-jarJsTestDriver-1.3.4.b.jar–port9876–browser“[测试机上的IE路径]“,”[测试机上的Firefox路径]“,”[测试机上的Chrome路径]“,”[测试机上的Safari路径]“
这个例子中用了下面脚本:
java-jarJsTestDriver-1.3.4.b.jar–port9876–browser“C:
\Users\jianfei.jujf\AppData\Local\MozillaFirefox\firefox.exe”
更多命令参考官方文档
∙在simply目录下建run.bat文件,内容如下:
java-jarJsTestDriver-1.3.4.b.jar–testsall>d:
\result.txt
更多命令参考官方文档
最后,先运行server.bat,其实就是启动了一个JsTestDriver的服务器,脚本会把浏览器打开,浏览器打开后,运行run.bat,单元测试代码就开始运行了,并生成测试结果。
注意,jsTestDriver是基于Java的,所以要先确保运行bat脚本的机器已经安装了java,并且配置了环境变量。
settingrunnermodeQUIET
..
Total2tests(Passed:
2;Fails:
0;Errors:
0)(1.00ms)
Firefox12.0Windows:
Run2tests(Passed:
2;Fails:
0;Errors0)(1.00ms)
jsTestDriver采用自己的测试界面,并没有像jasmine那样采用一个html来作为测试入口,来加载js源代码,测试用例和显示测试结果。
那如果有dom操作,以及dom事件相关的单元测试怎么办?
接着看下面如何解决dom依赖以及事件模拟问题。
解决dom依赖
JsTestDriver采用了自己的测试界面,那要解决dom依赖问题,那就要把测试依赖的html片段加到JsTestDriver的片段中。
思路:
采用同步的ajaxcall把html片段读取到测试端浏览器,避免异步请求等待。
读取html片段后,放入一个div容器,将div容器append到jsTestDriver的测试页面中。
根据这个思路,编写了jasmine-fixture.js,代码如下:
(function(){
vardefaultConfig={
wrapperHook:
'J_JF',
/**
*html片段插入dom的容器id
*/
wrapperTpl:
'${fixture}
for(;iaHtml.push(this._getHtml(urls[i]));
}
}
returnaHtml.join('');
},
_substitute:
function(str,obj){
str=str||"";
returnstr.replace(/\\?
\$\{([^{}]+)\}/g,function(match,key){
if(match.charAt(0)=="\\"){
returnmatch.slice
(1);
}
return(obj[key]!
==undefined)?
obj[key]:
"";
});
},
_createXHR:
function(){
varxhrObj;
if(window.XMLHttpRequest){
try{
xhrObj=newXMLHttpRequest();
}catch(e){
}
}elseif(window.ActiveXObject){
try{
xhrObj=newActiveXObject("Msxml2.XMLHTTP");
}catch(e){
try{
xhrObj=newActiveXObject("Microsoft.XMLHTTP");
}
catch(e){
}
}
}
returnxhrObj;
},
_getHtml:
function(url){
var_this=this,
sHtml,
path=_this.path,
sUrl=path.match('/$')&&path+url||path+'/'+url,
xhrObj=_this._createXHR();
if(xhrObj){
try{
xhrObj.open('GET',sUrl,false);
xhrObj.onreadystatechange=function(){
if(xhrObj.readyState===4){
if(xhrObj.status===200){
sHtml=xhrObj.responseText;
}
}
};
xhrObj.send(null);
}catch(e){
//Handleerror
}
}
returnsHtml;
},
_appendTo:
function(html){
vardoc=document,
oDiv,
wrapperTpl=this.wrapperTpl,
wrapperHook=this.wrapperHook,
oWrapper,
wrapperedHtml;
if(html){
oWrapper=doc.getElementById(wrapperHook);
if(oWrapper){
oWrapper.innerHMTL=html;
}else{
oDiv=doc.createElement('div');
wrapperedHtml=this._substitute(wrapperTpl,{
'fixture':
html
});
oDiv.innerHTML=wrapperedHtml;
doc.body.appendChild(oDiv.children[0]);
oDiv=null;
}
}
},
clean:
function(){
varoWrapper=doc.getElementById(this.wrapperHook);
if(oWrapper){
oWrapper.innerHTML='';
}
}
};
jasmine.Fixtures=Fixture;
jasmine.getFixtures=function(){
returnjasmine._currentFixtures_=jasmine._currentFixtures_||newjasmine.Fixtures();
};
})();
window.JF={};
beforeEach(function(){
JF=newjasmine.getFixtures();
});
如何使用?
看下面列子:
src/dom.js代码:
(function(){
vardoc=document;
varDom={
byId:
function(id){
returndoc.getElementById(id);
},
byTag:
function(tagName){
returndoc.getElementsByTagName(tagName);
}
};
window.Dom=Dom;
})();
src/dom.spec.js代码:
describe('DomClassTest',function(){
varurl1='test.html';
beforeEach(function(){
JF.load(url1);
});
it('shouldgetthecorrectdomnodebybyId',function(){
expect(Dom.byId('test')).not.toBeNull();
});
it('shouldgetthecorrectdomnodesbybyTag',function(){
vardEms=Dom.byTag('em');
expect(dEms).not.toBeNull();
expect(dEms.length===2).toBeTruthy();
});
});
spec/fixtures/test.html代码: