前端测试

Post on 12-Sep-2014

25 Views

Category:

Technology

4 Downloads

Preview:

Click to see full reader

DESCRIPTION

前端测试

TRANSCRIPT

前端测试

赵勇 / 淘宝 UED / 前端 / 遇春(花名)

个人介绍:

前端测试

前端 测试

Why

找一个说服自己的理由

• RIA

• Base on Browser

• Heavy Javascript

• Html 5

产品的变化

Server Browser

Server Browser

开发量的变化

前端质量

内部质量

可维护性性能设计模式开发效率

外部质量

功能

界面

前端关注点的变化

前端团队的变化

游击队

正规军

测试同学:

“ 前端的问题越来越多了”

别再找理由了先搞起来再说

前端 测试

How

前端测试目标

• 产品界面

• 功能可用

• 性能高效稳定

• 代码可维护性强

声音“ 前端不好测”“ 界面老是改,改完用例就没用了”“ 单元测试不好做,很难隔离,不好做mock”

“ 业内没有成熟的实践”“ 项目太紧,没时间”“ 前端测试性价比不高”

前端的痛

Ajax

闭包

Dom

异步

匿名函数

浏览器

兼容性

面向过程

性能

分而治之

Ajax

闭包Dom

异步

匿名函数

浏览器

兼容性

面向过程

性能

Dom 测试 单元测试功能测试 性能测试

Dom 测试• 结构,布局• 兼容性

单元测试• 对象属性,方法• 过程函数

功能测试• 过程

性能测试• 动态执行响应

前端测试

DOM 测试

测试目标• DOM 结构完整

• 模块布局样式无错乱

• 浏览器兼容性

谁动了我的 TAG

</div>

• 加个样式, Ie6 乱掉了

• 开发 html 嵌套时,标签没闭合

• 某个元素的样式名写错了

• …

还有

DEMO

http://www.labs.com/sample/ershou.html#testOn

代码

describe('UI-logo',function(){

var logo = KISSY.get('#logo');

it('exist',function(){

expect(logo).toBeNode();

});

})

代码describe('UI-logo',function(){

var logo = KISSY.one('#logo');

it('position is right',function(){

var oPos = (KISSY.DOM.viewportWidth() – 990)/2;

expect(logo.width()).toNear(177);

expect(logo.height()).toNear(48);

expect(logo.offset().left).toNear(oPos);

expect(logo.offset().top).toNear(47); });

})

代码describe('UI- 新鲜货 ',function(){

var freshItem = KISSY.one('#J_FreshItems');

it('childNode is right',function(){

expect(freshItem.children().length).toBe(2);

});

})

功能测试

功能测试目标 • 功能可用

• 交互过程正确

DEMO

http://www.labs.com/sample/ershou.html#testOn

代码describe(' 功能 - 城市切换 ', function(){

var cityTrigger = KISSY.get('.J_CityPicker'),

cityPopup = KISSY.get('.more-city-bd');

it(' 打开地区浮出层 ', function(){

jasmine.simulate(cityTrigger, 'mouseover');

expect(cityPopup).toBeVisible();

});

})

性能测试

性能测试目标 • 同步执行耗时

• 异步响应耗时

DEMO

http://www.labs.com/sample/ershou.html#testOn

代码describe(' 功能 - 城市切换 ', function(){

var cityTrigger = KISSY.one('.J_CityPicker').getDOMNode(),

cityPopup = KISSY.one('.more-city-bd').getDOMNode();

it(' 打开速度 ', function(){

var start = +new Date();

jasmine.simulate(cityTrigger, 'mouseover');

var end = +new Date();

var runtime = end-start;

expect(cityPopup).toBeVisible();

expect(runtime).toBeLessThan(500);

});

})

代码describe(' 搜索推荐 - 城市切换 ',function(){

var searchInput = KISSY.get('#J_TBSearchQuery');

it(' 自动搜索推荐 ', function(){

searchInput.value = 'nokia';

jasmine.simulate(searchInput,'keydown');

waits(1000);

runs(function(){

var suggestContainer = KISSY.get('.ks-suggest-container');

var suggestContent = KISSY.one('.ks-suggest-content').children().length;

expect(suggestContainer).toBeVisible();

expect(suggestContent).toBe(1);

}); });})

单元测试

单元测试目标• 函数

• 对象的属性和方法

• 业务逻辑

代码可测试性问题

1.面向过程,过程嵌套

2.太多的 DOM 操作

3.展现逻辑和业务逻辑混淆

4.闭包

语言特性

1.本地对象 & 宿主对象

2.静态作用域链

3.动态 & 弱类型

提升可测试性

抽象

绑定事件回调

更新 DOM

处理数据

从 UI 层获取数据

定义变量

定义常量

function(){

var CONSTANTS = 'constants value',ELEMENTID = 'J_EId';

var localVariable,result;

var element = KISSY.one(ELEMENTID);

localVariable = element.attr('data-need');

result = handle(localVariable);

update(element,result);

E.on(element, 'event', EventHandler);

}

过程式函数结构

数据属性

DOM 相关属性

处理数据的方法

操作 DOM 的方法

功能或过程方法

Obj : {

attr-data:'value',

attr-ui:D.get('xid'),

method-data:function(){// deal attr-data...

},

method-ui:function(){// deal attr-ui...

},

process:function(){method-data();method-ui();

}}

对象结构

1. 单一职责法则,更细颗粒的过程抽象

2. 避免使用匿名函数

3. 将数据处理和 DOM 操作完全分开

4. 分离业务逻辑和展现逻辑

5. 减少闭包,为闭包中待测函数提供全局命名空间

如何抽象

过程抽象范例

//...calculate point

var level;if (point < 100){

level = ' 文艺青年 ';}else if (point >= 100 && point < 200){

level = ‘2B 青年’ ;}else{

level = ' 普通青年‘ ;}

//...use level

function getLevel(point){var level;if (point < 100){

level = ' 文艺青年 ';}else if (point >= 100 && point < 200){

level = '2B 青年‘ ;}else{

level = ' 普通青年‘ ;}return level;

}

//...var level = getLevel(point);//...

闭包内函数暴露测试接口范例

(function(){var a = 1;function method1(m){

return a + m;}testTarget = window['testTarget‘] || {};testTarget.method1 = method1;

})();

Event.on('#content','blur',function(){

if(this.value === ''){

alert(' 输入有误,不能为空 ')

}

})

逻辑分离范例

hasError(this.value)

showError()

Event.on('#content','blur',function(){if(hasError(this.value)){

showError();}

})function hasError(v){

return isBlank(v);}function isBlank(v){

var BLANK = '';return KISSY.trim(v) === BLANK;

}function showError(){

var errMsg = ' 输入有误,不能为空 ';alert(errMsg);

}

提升可测试性

分层

Javascript

1.构建 Js 本地对象

2.处理数据逻辑

3.与 Server 通信

4.添加事件回调

5.操作 DOM , BOM

BOM

UI

Model

DOM

Javascript

Server

Control

View Control

Model

obj

obj obj

objobj

obj

obj obj

obj instantiation

process

bindEvent

MVC 对象结构

ViewObj

_Attr : value1

AttrEl : someEl

getUIData : function(){//…

}

setUI : function(){//…

}

1.获取 DOM , BOM 数

2.修改 DOM 和 BOM

3.处理展现层逻辑

ModelObj

_Attr1 : value1

_Attr2 : value2

_Method : function(){//…

}

Method : function(){//…

}

1.建立业务数据模型

2.处理数据间的逻辑关系

3.提供数据访问器

4.预留数据事件接口

ControlVar objUI = new View();Var obj = new Model();

Function Process1(){//…

}Function Process2(){

//…}

E.on(someEl,’event’,process1);

1.对象实例化

2.初始化

3.定义过程 , 实现

view 和 model 层对

4.事件绑定

1. 可测试性提升

2. 各层关注分离,提升可扩展性

3. 业务逻辑和展现逻辑分离, UI 修改更安全

分层的好处

1. 面向过程面向对象,推行成本较大

2. 对于简单的过程,反而增加可理解性

3. 对开发人员的抽象能力要求较高

分层的问题

DEMO

http://www.labs.com/mvc/talk.html

Dom 测试 单元测试

功能测试 性能测试

如何应用?

单元测试

性能测试功能测试

DOM 测试

逻辑复杂型首页型

交互型

3QA

top related