版本:1.0
jasmine-kissy是为了方便基于kissy的代码进行单元测试,而向Jasmine添加的扩展。
jasmine-kissy主要扩展了如下四个功能
- 1.增加kissy的ajax mock功能(伪造ajax的假数据方便进行ajax测试)
- 2.增加velocity mock功能,直接读取vm模版,使用伪数据mock出测试所依赖的html片段(dom)
- 3.增加html mock功能,同步加载html片段并插入到测试运行页中
- 4.增加用于KISSY的machers,只作用于KISSY的Node模块。
##如何测试kissy的异步加载模块
有2种方法:
- 干掉异步加载过程,静态引用模块文件
- 异步加载完模块文件后,再执行jasmine运行测试用例
这里明河推荐使用第二种方法,虽然会麻烦些。
####引入runner.js
<script type="text/javascript" src="http://a.tbcdn.cn/s/kissy/gallery/jasmine-kissy/1.0/runner.js"></script>
####加载指定测试模块文件
KISSY.use('jasmine/runner',function(S,runner){
runner('specs/ajax-mock-spec');
})
如果你需要加载多个测试模块:
KISSY.use('jasmine/runner',function(S,runner){
runner(['specs/ajax-mock-spec','specs/html-mock-spec']);
})
留意: specs模块包,需要自己配置下,比如:
KISSY.use('jasmine/runner',function(S,runner){
runner(['specs/ajax-mock-spec','specs/html-mock-spec'],{ name:'specs', path:'./', charset:"gbk" });
})
####测试模块如何写?
KISSY.add(function (S, Node, io, demo) {
describe('runner test', function () {
it('runner test', function () {
});
});
}, {requires:['node','page/mods/demo' ]});
describe包裹在add()内,然后requires源码模块js。
##ajax mock
jasmine-kissy中的ajax mock远比jasmine ajax来的强大。
- 你无需修改任何源码js
- 能够直接截获接口,当脚本向接口发送请求时,直接劫持到伪结果集
- 简单,根据status自动返回对应的结果集,你只需要书写一份伪数据
- 完美支持jsonp,无需任何标识
- 支持kissy的所有io方法,比如get()、post()、jsonp等
目前不支持mock io.upload()。
demo传送门:mock api test
####引入依赖文件
想要mock kissy的ajax,需要覆盖"ajax/base"模块,所以不能引入kissy.js文件,只能引用seed-min.js,然后引入jasmine-kissy.js文件,比如下面的代码:
<script type="text/javascript" src="http://a.tbcdn.cn/s/kissy/1.2.0/??seed-min.js,dom-min.js,event-min.js,node-min.js"></script>
<script type="text/javascript" src="http://a.tbcdn.cn/s/kissy/gallery/jasmine-kissy/1.0/jasmine-kissy.js"></script>
留意必须开启KISSY的debug标识:
var S = KISSY;
S.Config.debug = '@DEBUG@';
####ajax的伪数据
KISSY.add(function (S) {
return [
{
status:200,
responseText: '{"status":1,"name":"minghe"}'
},
{
status:500,
responseText:''
},
{
status:200,
data:{site:'36ria'},
responseText: '{"status":2,"site":"36ria"}'
},
{
status:200,
responseText: 'jsonp1234({"status":1,"name":"minghe"})'
},
{
status:200,
data:{site:'36ria'},
responseText: 'jsonp5454({"status":2,"site":"36ria"})'
}
]
});
一份伪数据为一个数组,包含各种状态下的结果集,比如成功,失败,传入不同参数时。
- status:值为200时,为成功状态,会触发io的sucess事件
- data:为前端传递给服务器端的参数,对应io的data参数,当不存在匹配时,mock类会返回不带参数的结果集
- responseText:文本结果集,留意jsonp时的文本,mock类会自动判断jsonp
####mock 的使用
var api = "http://service.taobao.com/support/minerva/ajax/refundPlugAjax.htm";
//使用mock
io.useMock = true;
//装入伪数据
io.install(api, simpleData);
//使用成功状态的假数据
io.use(api, 200);
io.useMock=true 开启ajax mock
io.install(api, simpleData) 装入伪数据,simpleData即上面的demo数据
io.use(api, 200) 使用成功状态的伪数据
接下来可以使用io方法试试
// 用于ajax的回调测试
onSuccess = jasmine.createSpy('onSuccess');
//触发异步请求
S.io({
url:api,
type:"GET",
success:function (data, status) {
onSuccess(data);
}
});
var successResult = onSuccess.mostRecentCall.args[0];
expect(onSuccess).toHaveBeenCalledWith(jasmine.any(Object));
expect(successResult.status).toEqual(1);
expect(successResult.name).toEqual('minghe');
onSuccess方法将会被执行一次,并且它的第一个参数的值为:
{"status":1,"name":"minghe"}
如果你想要mock 接口失败时的情况
it('use error data mock',function(){
//使用失败状态的假数据
io.use(api,500);
onError = jasmine.createSpy('onError');
//触发异步请求
S.io({
url:api,
type:"GET",
error:function(data){
onError(data);
}
});
expect(onError).toHaveBeenCalled();
});
mock jsonp的接口情况也是如此
io.use(api,200);
onSuccess = jasmine.createSpy('onSuccess');
//异步请求带上不存在的参数
S.io.jsonp(api,function(data){
onSuccess(data);
});
var successResult = onSuccess.mostRecentCall.args[0];
expect(onSuccess).toHaveBeenCalledWith(jasmine.any(Object));
expect(successResult.status).toEqual(1);
expect(successResult.name).toEqual('minghe');
如果你想要mock,不同传参下的接口
io.use(api,200);
onSuccess = jasmine.createSpy('onSuccess');
//异步请求带上指定参数
S.io({
url:api,
type:"GET",
data:{site:'36ria'},
success:function (data, status) {
onSuccess(data);
}
});
var successResult = onSuccess.mostRecentCall.args[0];
expect(onSuccess).toHaveBeenCalledWith(jasmine.any(Object));
expect(successResult.status).toEqual(2);
expect(successResult.site).toEqual('36ria');
所有的mock都非常简单,你无需修改源码js,mock类会自动处理,你唯一要做的就是install伪数据,然后use你想要的结果集
##velocity mock的使用
大多数业务逻辑的js测试都依赖于dom结构(采用mvc框架会好很多),velocity mock的功能是直接拉取工程中的vm文件,然后渲染出html片段,插入到body中。
####我们准备一个vm模版
list.vm内容如下:
<div class="scroller">
<div class="ks-switchable-content">
#foreach($msg in $!currentProofMsg)
<div class="list-item J_ListItem">
#if($!msg.attachment)
#set($newUrl ="$!msg.attachment"+"_120x120.jpg")
#set($originalUrl="$!msg.attachment"+".jpg")
<img class="J_ImgDD" data-original-url="$refundImageServer.getURI("refund/$originalUrl")" src="$refundImageServer.getURI("refund/$newUrl")"/>
#end
<div class="image-comment">
<img class="comment-icon" src="http://img02.taobaocdn.com/tps/i2/T1yhMcXbBdXXb38KzX-15-13.png"/>
<div class=" J_ImageCommentContent">
<p class="comment-author">$!roleName的留言:</p>
<p>$!msg.content</p>
</div>
</div>
</div>
#end
</div>
</div>
伪数据list.json内容如下:
{
"MAP":{
"control":"./specs/vms"
},
"type":1,
"currentProofMsg":[
{"attachment":"http://img01.taobaocdn.com/imgextra/i1/10361016579368429/T1zbCTXfdmXXXXXXXX_!!413810361-0-tstar","roleName":"您","content":"这是一条留言"},
{"attachment":"http://img01.taobaocdn.com/imgextra/i1/10361016579368429/T1zbCTXfdmXXXXXXXX_!!413810361-0-tstar","roleName":"您","content":"这是一条留言"}
]
}
MAP是特殊关键字,后面明河会解释。
####在spec文件中引入HtmlMock
KISSY.add(function (S, Node,HtmlMock) {
var $ = Node.all;
var htmlMock = new HtmlMock();
describe('velocity mock test', function () {
})
},{requires:['node','jasmine/htmlMock']});
####读取vm模版和伪数据
KISSY.add(function (S, Node,HtmlMock) {
var $ = Node.all;
var htmlMock = new HtmlMock();
describe('velocity mock test', function () {
it('正确读取并解析vm模版',function(){
htmlMock.load('./specs/vms/list.vm','./specs/vms/list.json');
expect($('.scroller')).toExist();
expect($('.J_ListItem').length).toBe(2);
expect($('.J_ImgDD').length).toBe(2);
})
})
},{requires:['node','jasmine/htmlMock']});
load()
方法有二个参数:
- vm模版路径,必填
- 伪数据路径,可以直接传入json数据,比如下面的代码
htmlMock.load('./specs/vms/list.vm',{
"MAP":{
"control":"./specs/vms"
},
"type":1,
"currentProofMsg":[
{"attachment":"http://img01.taobaocdn.com/imgextra/i1/10361016579368429/T1zbCTXfdmXXXXXXXX_!!413810361-0-tstar","roleName":"您","content":"这是一条留言"},
{"attachment":"http://img01.taobaocdn.com/imgextra/i1/10361016579368429/T1zbCTXfdmXXXXXXXX_!!413810361-0-tstar","roleName":"您","content":"这是一条留言"}
]
});
####MAP的用途
MAP用于指定vm模版中依赖模版的路径,比如你的vm可能会出现#parse("control/listImageComment.vm")
这样的引用,这时候就需要指定下control
的路径映射。
####clean:清理模版
测试运行结束后建议clean下模版,避免影响其他测试的准确度。
htmlMock.clean('./specs/vms/list.vm')
,不填入第一个参数时,会清理所有的html片段,不推荐!!!
加载的html片段会放在页面的测试容器内,容器id为#J_JF
。
加载的片段会放入缓存,避免重复加载。
html mock与velocity mock基本一样,更为简单,不需要第二个伪数据参数。
假设在你的specs/fixtures
目录有个html片段文件jasmine-kissy_fixture.html
。
文件的内容如下:
使用如下语法加载这个文件:
`htmlMock.load('./specs/jasmine-kissy_fixture.html');`
你可以测试下#test这个div是否存在:
`expect('#test').toExist();`
(ps:toExist()是jasmine-kissy新增的macher,用于测试节点是否存在)
toExist()
测试节点的存在性toHasClass()
测试节点是否拥有指定的class名toHasAttr()
测试节点是否拥有指定的属性值toHasProp()
测试节点是否拥有指定的property值toHasData()
测试节点是否拥有指定扩展属性值toContain()
测试节点是否有子节点toEqualValue()
测试节点的的value值toEqualText()
测试节点的text
示例代码:
expect($('#test')).toHasClass('test-wrapper');
expect($('#test')).toEqualText('my name is minghe.');
- Jasmine 1.1
- KISSY 1.2