AngularJS实战第一章

AngularJS实战

作者:kimmking、大漠穷秋、任富飞

问题反馈:kimmking@163.com

AngularJS介绍–AngularJS的前世今生

AngularJS

AngularJS是什么

在Web开发领域,我们一般使用HTML作为前端页面元素的声明式语言,使用CSS技术作为展示样式的描述语言,Javascript作为业务处理交互的命令式语言。当我们构建非常复杂的Web应用时,纯粹而有限的HTML就显得非常不足,Javascript本身也会随着项目代码量的膨胀而难以维护和管理,研发工期和成本也会随之难以控制。这时候,我们一般使用一些类库(例如JQuery、Dojo等)或框架(例如Backbone、Ember、ExtJS等)来提升开发效率,进而降低项目的工期和成本,也方便后续的维护和管理。

而AngularJS不仅是一个理念先进(逼格高)的前端开发框架,更是一种端对端(End to End)的解决方案。AngularJS遵从架构设计中的MVC模式,提倡展现、数据和逻辑处理组件的松耦合(类似Flex和WPF)。AngularJS通过指令技术对传统HTML实现了自然扩展,通过编译技术实现了数据模型与展现视图的双向自动同步,从而消除了前端开发中繁琐复杂的DOM操作(想想看那些一片片的selector)。最后再通过模块化设计解决了JS代码管理维护和按需加载的问题,解放了广大前端程序员(以及后端程序员)同胞完成前端开发任务的生产力。而且这种解耦本身,也对前端的自动化测试技术提供了良好的支持。

AngularJS有多火

这两年可以说是AngularJS受欢迎程度爆发性增长的两年。AirPair做过一个三个主流JS框架AngularJS、Backbone、Ember的对比,AngularJS的热度远远超过了另外两个框架。参见下图:

  • 各网站上三种框架的统计数据(高出一大截)

AngularJS vs. Backbone.js vs. Ember.js

  • Google趋势指数中的关注程度(甩出八百里)

AngularJS vs. Backbone.js vs. Ember.js

AngularJS的设计理念

一句话来描述AngularJS的设计理念那就是:简化对Web开发者的经验要求,或者说让Web开发变得简单、同时让Web本身变得功能更强。所以,AngularJS框架强调UI应该是用HTML声明式的方式构建,数据和逻辑再进一步的由框架提供的机制自动匹配绑定。

作者Misco在采访中表示,AngularJS框架的一些设计灵感来源于自己在Adobe公司从事的Flex开发经历。

AngularJS的特点

  • 上手简单:通过学习AngularJS的一些概念和常见用法,即可在不需要大量了解DOM操作的情况下开发前端Web应用。
  • 开发效率:一方面AngularJS相对于传统前端开发能减少大量的操作代码(双向绑定、自动注入),另一方面也通过前后端分离、合理的模块化组织项目结构降低了耦合、使开发者更关注于每一个具体的逻辑本身,从而加快了开发速度,也利于提升系统的质量。
  • 运行效率:纯静态化便于前后端的缓存优化,按需加载也降低服务端IO的压力。当然不得不提的是,如果双向绑定的数据对象数据过多,比如多于2000个,会导致浏览器页面的渲染速度较慢。对于这一点,由于一页内展示可见的区域有限、并且用户一个时间点能关注内容也有限,我们一般可以采用数据分页加载等方式降低一次绑定的数据对象数量。
  • 适用范围:我们知道软件领域没有银弹,没有一种东西能解决一个大领域里的所有问题。所以,AngularJS也有自己的适用范围。比如像Web游戏、在线图形编辑等这些需要频繁操作DOM的前端,就不适合用AngularJS来开发。一般来说,AngularJS特别适合基于CRUD的业务系统Web应用的前端开发,而且幸运的是目前这个地球上绝大部分的Web应用是这种。

起源

AngularJS Misko Hevery

AngularJS最初由Misko Hevery和Adam Abrons于2009年开发,后来成为了Google公司的项目。后来Abrons离开了AngularJS,但在Google工作的Misko Hevery和谷歌员工Igor Minar和Vojta Jina等继续开发和维护这个库。
创始人Misko Hevery加入Google公司之前,曾在Intel、Xerox(施乐)、Sun和Adobe公司工作过,主要从事数据库/后端方面的工作。加入Google公司后,Misko Hevery开始转向自动化测试,AngularJS这项工作的主要目的是改进Google的开发者工作效率,从而改善代码库。

AngularJS的起源还有个有趣的小故事。最开始的时候,Misko Hevery和Adam Abrons搞了一个做在线JSON存储服务的网站“GetAngular.com”,AngularJS就是为了这个项目开发的。虽然这个项目有了一些注册用户,但是两人还是决定把AngularJS作为一个开源库发行。2010年的时候,Misko Hevery参与Google Feedback项目。项目团队使用GWT进行开发,在花了6个月的时候以后,编写了17000行代码。随后,Misko Hevery花了3周将这17000行代码的程序使用AngularJS重写,结果是压缩成了令人吃惊的1500行,不到原来的十分之一。这引起了Google的重视,公司也开始资助其团队全职从事开发AngularJS。

后来的事儿,大家都知道了。AngularJS越来越火,有了更多的支持,吸引了来自全球的千百名开源爱好者为AngularJS项目做出了贡献。随着项目的发展和广泛的传播,越来越多的开发者在自己的项目中选择使用AngularJS,学习和使用AngularJS已经成为了前端开发中的一股潮流。

这个JS库为什么叫AngularJS?JS代码的命名空间为什么叫ng?

官方的解释是,因为HTML里普遍使用尖括号(英文叫Angular Brackets),而ng的发音跟Angular比较像。

但我们更倾向于认为 ng 是下一代(Next Generation)前端开发技术的意思。

现状

AngularJS目前最新的稳定版本是1.3.0。(截止到北京时间2015年1月24日,最新稳定版本是1.3.10,beta版本最新的是1.4.0-beta.1。)1.3.0版本主要有3个变动:

  1. 去掉了对IE8的支持(虽然IE6和IE7早就连微软自己都放弃治疗了,AngularJS官方还是提出了一些对IE6、7、8的兼容办法)
  2. 引入了单向数据绑定
  3. 删掉了一堆过时的API(据说是为了AngularJS2.0版本做准备)

AngularJS核心特性–JS的四个现代化

MVC模式

MVC模式大家应该都比较熟悉了。不管是java里的Struts、Spring MVC等框架,还是.Net里的ASP.NET MVC技术,都是典型的MVC模式。1979年,挪威计算机科学家、奥斯陆大学教授Trygve Reenskaug为施乐公司的帕罗奥多研究中心(Xerox PARC)设计GUI(图形用户接口)软件时(当时使用的是Smalltalk),正式提出了著名的MVC模式。

AngularJS

小八卦:Trygve Reenskaug的第一个主要的软件项目“Autokon”,在1963年开始投入使用,此后在全世界的范围内使用了30多年。

什么是MVC

MVC全称是Model View Controller,即模型(model)-视图(view)-控制器(controller)的缩写,即在项目设计和代码结构里把业务和控制逻辑、数据模型、界面展示这三部分解耦,方便各部分单独编写和维护,而且在数据和界面发生变化时,对业务和控制逻辑影响最小,有时候甚至时不需要重新编写业务和控制逻辑。由于有这样的优点,MVC很快被广泛应用到各种不同平台上的带有业务处理的图形化用户界面中。

AngularJS MVC

模型(Model):数据模型层,负责程序中数据逻辑的部分,一般主要是读写数据库。这一块对终端用户是不可见的。

视图(View):视图展示层,负责将数据以交互界面的形式展现为终端用户,视图一般是基于数据模型来组织的。这一块是软件中终端用户可以看到和操作的部分,比如前端开发使用HTML元素来实现UI界面。

控制器(Controller):逻辑控制层,负责处理业务逻辑和控制逻辑,处理视图里的数据输入,向模型层发送数据,从模型层获取数据,将数据传递到视图层进行展示等等。一般来说控制器充当模型和视图的黏合剂角色。

MVC的优点

AngularJS

MVC模式的优点大概有如下几条:

  • 职责清晰:MVC模式将原来都混在一起的复杂代码逻辑按不同的职责拆解成三个不同的部分,每一部分的职责和功能都相对单一,便于独立的设计和实现。
  • 代码分层模块化:我们知道将一个系统按业务功能竖向划分,就产生了不同的业务模块。而在同一个模块内,基于职责的横向拆解,项目代码结构就实现了分层的模块化(即我们常说的项目三层架构,3-Tier Architecture)。在这样的横切竖割以后,整个复杂的项目就被分解成了一个个非常小的模块结构,使得项目研发工作的计划安排和管理都很方便。
  • 耦合性低:将项目代码结构拆解到非常小的粒度以后,各个小的模块结构间依赖性降低,从而整个项目就降低了耦合性,整体复杂性也随之降低了。
  • 可重用性高:每个模块独立出来以后,抽象性更高,复用的可能性就更高。例如以前某个业务A中数据处理的代码都更界面UI的代码写在一起,除非其他模块B的数据和界面都跟一模一样才能复用业务A的这一块代码。现在我们把业务A按照MVC都拆解开以后,只要业务B的数据模型用的还是业务A背后的数据模型D,我们就可以在实现业务B的时候,把数据模型D复用、而不是重新写一遍。同理,视图层的一些表单经常也可以复用到不同的业务模块中去。
  • 可维护性高:代码干净了,不拖泥带水,发生变更时影响的范围最小,方便维护。结构清晰了,每块代码写到相应的目录结构下,有利于整个团队的项目大规模协同工作,同时新人加入团队或是新的团队接手项目,都会比较顺利。
  • 研发成本低:由于以上的优势,在项目规模比较大,UI和逻辑都相对复杂的情况下,MVC模式能明显地降低研发成本。

小提示:为什么GoF的23个设计模式中没有MVC模式?

大家可以上网搜索一下,有惊喜哦! :)

AngularJS的MVC

我们先看一个Hello Angular的小例子,然后基于例子了解下AngularJS中的MVC是怎么样的。

HelloAngular_MVC.html 文件:

<!doctype html>
<html ng-app>
    <head>
        <meta charset="utf-8">
    </head>
    <body>
        <div ng-controller="HelloAngular">
            <p>{{greeting.text}},Angular</p>
        </div>
    </body>
<script src="js/angular-1.3.0.js"></script>
<script src="HelloAngular_MVC.js"></script>
</html>

HelloAngular_MVC.js 文件:

function HelloAngular($scope) {
    $scope.greeting = {
        text: 'Hello'
    };
}

例子由两个文件组成,一个html文件,一个js文件。
这个html文件中除了要引入对应的js文件,还需要引入angular-1.3.0.js文件(可以在官网下载,也可以直接下载本书的示例代码包,其中包含了所有的例子代码和所需要的angular等依赖文件)。

我们可以看到在html文件中,有一个ng-controller,它的值为HelloAngular,而在js文件中定义了一个叫HelloAngular的函数。显然,这个js文件中定义的HelloAngular函数,就是MVC中的C控制器(Controller)

那MVC中的V,也就是视图(View)在哪儿呢?我们前面提到对用户展示的可见内容就是视图。那么我们在html文件中可以发现,p标签里就是我们对外展示的内容,那么p标签就是我们这个示例程序中的视图,也就是如下这句代码:

<p>{{greeting.text}},Angular</p>

MVC中的C和V都有了,那么M,也就是模型(Model)在哪里呢?在html文件的视图,也就是p标签里,我们看到用双花括号绑定了一个表达式greeting.text,那么这个东西是哪儿来的呢?让我们回到js文件中,可以看到有一个赋值:

$scope.greeting = {
    text: 'Hello'
};

这句代码是说,在$scope里,给greeting对象的text属性赋值为字符串Hello。视图中将要使用的数据是从这里引入的。所以,这个赋值就充当了MVC中的模型M的角色。至此,我们的第一个AngularJS示例程序中的MVC结构就齐备了。

让我们在浏览器里运行一下HelloAngular_MVC.html看看效果:

AngularJS Hello

可以看到展示出来的Hello,Angular,其中的Hello在html文件中并没有这个字符串,说明它就是来源于我们js中对模型的赋值。
回顾一下本示例中MVC的各部分:

  • 控制器:js中实现的、在html里的函数。
  • 视图:html中展示内容的p标签。
  • 模型:js里给绑定对象赋值的部分。

模块化

在上一节的例子里,我们可以发现定义的控制器HelloAngular是一个全局的JS函数。大家都知道大量地定义一些全局的函数和变量,会污染JS的全局上下文环境。那么AngularJS里怎么解决这个问题的呢?答案就是模块化。

什么是模块化

在C++、Java里,我们通过Namespace、Package的方式隔离开了相同类名的类,而在Python里,我们可以进一步的使用Module来聚合一定功能的代码。这些设计使得我们可以按照自己的需要放置某些类在同样的一个层级组织之下。在AngularJS里,我们也可以显式的定义一个模块(Module),然后将某个功能模块的所有逻辑代码(函数、变量等),按照一定的规则和结构封装到这个Module中,从而规范了项目结构的组织方式,同时也避免了全局环境污染。

小贴士:虽然模块化约束了代码中函数和变量的作用范围和使用方式,但是AngularJS的Module里通过依赖注入的方式,可以使得我们的代码更加的灵活方便。

AngularJS里的Module

AngularJS module

我们先举个栗子,看看AngularJS中Module的定义和用法。

HelloAngular_Module.html文件:

<!doctype html>
<html ng-app="HelloAngular">
    <head>
        <meta charset="utf-8">
    </head>
    <body>
        <div ng-controller="helloAngular">
            <p>{{greeting.text}},Angular</p>
        </div>
    </body>
    <script src="js/angular-1.3.0.js"></script>
    <script src="HelloAngular_Module.js"></script>
</html>

HelloAngular_Module.js文件:

var myModule = angular.module("HelloAngular", []);

myModule.controller("helloAngular", ['$scope',
    function HelloAngular($scope) {
        $scope.greeting = {
            text: 'Hello'
        };
    }
]);

我们可以看到,相比上一节的例子,html文件有一个微小变化:

  • html标签里多了一个属性:<html ng-app="HelloAngular">,这个属性告诉AngularJS框架,本页面使用HelloAngular这个模块来启动。

相比上一节的例子,js文件里有两个变化:

  • 多了一个模块的定义代码:var myModule = angular.module("HelloAngular", [])。这句代码使用angular.module方法定了一个名字叫HelloAngular的模块,并把这个模块赋值给了myModule变量。
  • 多了一个Controller的显式声明:myModule.controller("helloAngular", ['$scope' ...。这里在使用myModulecontroller方法,给HelloAngular模块添加了一个helloAngular的控制器。这样,helloAngular函数就变成了控制器定义时的一个内部函数。(这段代码请注意区分HelloAngular首字母的大小写。)

我们可以看到,AngularJS通过将Controller等资源聚合到一个显式定义的Module,从而避免了全局环境的污染。这个例子也可以从另一个方面说明我们修改了控制器层,但是视图层几乎不受到影响。

让我们在浏览器里运行一下HelloAngular_Module.html看看效果:

AngularJS HelloAngular

可以看到与上一节例子的运行效果相同。

小贴士:示例代码里还有一个值得一提的地方,就是myModule.controller创建控制器的时候,传递了一个'$scope'参数,而后面的控制器函数声明里使用了一个叫$scope参数,这个参数会在控制器函数被调用时自动作为参数注入到函数。这就是AngularJS的依赖注入。熟悉后端Web开发的同学们可以参考Spring MVC中的参数自动注入。

Module在AngularJS中的重要性

大家在开始学习时可能会觉得AngularJS中有很多概念,有Module、有Directive、有Service、有Filter等等。大家一定要抓住一个点,一切都是从Module开始的。开始使用AngularJS开发时,要先考虑Module,只有先有了一个Module,才能在模式上调用Service、调用Directive等。这就是为什么AngularJS中Module很重要的原因。

指令系统

指令系统(Directive)可以说是AngularJS中最有特色、最吸引人的功能特性。

AngularJS中的指令(Directive)

HelloAngular_Directive.html文件:

<!doctype html>
<html ng-app="MyModule">
    <head>
        <meta charset="utf-8">
    </head>
    <body>
        <hello></hello>
    </body>
    <script src="js/angular-1.3.0.js"></script>
    <script src="HelloAngular_Directive.js"></script>
</html>

HelloAngular_Directive.js文件:

var myModule = angular.module("MyModule", []);
myModule.directive("hello", function() {
    return {
        restrict: 'E',
        template: '<div>Hi everyone!</div>',
        replace: true
    }
});

相对于前面的例子,有两个不同的地方:

  • HelloAngular_Directive.html文件中,我们在原来用p标签实现视图的地方,加了一个<hello></hello>标签。
  • HelloAngular_Directive.js文件中,在模块里使用directive方法创建了一个解释hello标签的函数,使用<div>Hi everyone!</div>作为模版来渲染hello标签。

在浏览器中运行HelloAngular_Directive.html,效果如下:

AngularJS directive_demo

可以看到页面输出了Hi everyone!。按F11打开浏览器的调试功能,可以看到现在的源码:

AngularJS directive_hello

这说明页面上的hello标签,已经被<div>Hi everyone!</div>替换掉了。

小贴士:示例代码中的restrict: ‘E’和replace: true的作用会在后面Directive的章节里详细的讲解。

指令(Directive)的好处

AngularJS directive

正常的html里写hello标签是不会被浏览器处理的,而在AngularJS里这么写就可以实现自定义的标签处理实现指令系统,这就像是JSP技术里的标签库。这样我们可以根据自己的需要,封装出来很多功能组件,做一大堆指令在需要的时候调用。

小贴士:每个html示例代码中的开头都有<html ng-app="HelloAngular">,其中的ng-app就是AngularJS自定义的指令。那么这个指令是干什么的呢?

我们知道每个程序都有一个入口点,比如Java的main函数。AngularJS检测到html标签里有ng-app这个指令时,就知道往后的所有内容都归AngularJS来管了。既然是入口点那么每个程序只能有一个,所以ng-app指令在每个单页的AngularJS应用中只能出现一次。

双向数据绑定

AngularJS的第四个核心特性就是双向数据绑定,就是说数据模型层的变量可以绑定到前端视图层的内容上、前端视图层的内容上的数据也可以自动同步到数据模型层中去。目前大部分前端框架都只是实现了单向的数据绑定,比如jQueryUI、BackBone、Flex等。这也是吸引很多人使用AngularJS的一个重要原因。

BackBone官方网站上解释自己不实现双向数据绑定的原因是因为双向数据绑定机制用得比较少。

单向数据绑定机制

OneWayDataBinding

我们先来看看经典的单向数据绑定处理流程:在单向数据绑定中我们一般先实现一个模板(Template),再实现我们的数据模型(Model),这里的数据可能是从后端服务器读取出来的。然后通过数据绑定机制,把模板和数据结合在一起,生成一段html标签,最后把html片段插入到文档流里面。

我们可以发现,这个处理模式中,html片段一旦生成就无法再改变了:如果有新的数据过来,我们只能先清空原先的内容,把这个处理流程整个重新执行一遍。我们使用JQuery等框架就会有这些的一些问题。

双向数据绑定机制

TwoWayDataBinding

AngularJS认为单向绑定的处理模式非常的不优雅,所以就设计实现了双向的数据绑定机制。AngularJS认为视图和模型应该是绑定在一起的:当视图发生变化的时候,模型也自动发生变化;当模型发生变化的时候,视图自动会刷新显示新的内容。很显然这里需要借助一个事件机制来实现双方的协调一致。AngularJS一直监听数据和视图的变动事件,并在事件发生时将一方的变动内容同步到另一方,从而实现动态的、局部的、实时的刷新。

什么样的视图最容易发生变化呢?

一般情况下,我们在视图层使用表单收集用户录入的数据,所以表单这种视图是最容易发生变化的。

AngularJS的双向数据绑定示例

最后我们通过一个例子来演示AngularJS中的双向数据绑定。

HelloAngular_TwoWayDataBinding.html文件:

<!doctype html>
<html ng-app>
    <head>
        <meta charset="utf-8">
    </head>
    <body>
        <div>
            <input ng-model="greeting.text"/>
            <p>{{greeting.text}},AngularJS</p>
        </div>
    </body>
    <script src="js/angular-1.3.0.js"></script>
</html>

示例代码里,我们使用一个greeting.text表达式同时绑定到一个文本框和一个p标签,从而实现这个文本框和p标签的数据保持联动刷新,文本框内容变化时,p标签自动同步。

在浏览器中运行HelloAngular_TwoWayDataBinding.html文件,然后在文本框中输入文字,效果跟我们的预期一致。

TwoWayDataBinding

前端开发环境介绍–工欲善其事必先利其器

人类学会使用工具,从而解放了生产力,创造了整个文明。对于我们前端技术人员来说,一套顺手的工具,就像是行走江湖的大侠随身带了一口削铁如泥的宝刀,解放我们的双手和大脑,让我们可以把更多宝贵的时间和精力放到创造更美好的应用上。本节我们就来看看怎么打造一款适合AngularJS开发的前端工具箱。

前端自动化测试工具的示例

我们可以先看看前端自动化测试工具的例子:
安装Git、NodeJS、NPM、Bower、Protractor、Chrome等工具的例子先略过,本节后面会详细讲解。

从Github下载官方测试项目angular-phonecat的源码到本地目录:

git clone https://github.com/angular/angular-phonecat

在打开一个命令行窗口,在源码所在目录执行:

npm start

效果如下:

Protractor Server Access

在打开一个命令行窗口,在源码所在目录执行:

npm run protractor

效果如下:

Protractor Server Access

Protractor配置完成后,自动打开Chrome浏览器执行前端测试脚本,可以看到自动执行测试的效果跟人工操作界面是完全一样的:

Protractor Server Access

Protractor Server Access

执行完以后可以在启动Protractor的控制台看到测试所消耗的时间为27.392秒,执行了7个测试用例,11个断言,失败了0个:

selenium standalone is up to date.
chromedriver is up to date.

> angular-phonecat@0.0.0 protractor D:\kk\git\angular-phonecat
> protractor test/protractor-conf.js

Using ChromeDriver directly...
.......

Finished in 21.392 seconds
7 tests, 11 assertions, 0 failures

同时可以在启动http-server的控制台看到所有的浏览器请求:

Protractor Server Access

前端需要什么样的开发环境

在实际搭建拉风的开发环境之前,我们先来看看为什么前端需要一套工具,需要什么样的工具。

我们知道像后端Java开发,有Eclipse/MyEclipse、IntellJ IDEA、NetBeans这样的神器,像Dotnet开发有Visual Studio.NET这种重量级的核武器。而前端开发领域里连一款像样的调试器都没有。砍柴不误磨刀工,所以打造一身好装备就是一个非常紧迫的任务。我们来看看,整个前端开发过程中,需要哪些工具:

  • 代码编辑工具:它应该足够强大、灵活,响应速度快,支持各种语法高亮、提示、格式化等能加速我们把脑袋中的想法落地实现的功能特性。

  • 断点调试工具:这个是很显然的,代码编写过程中,我们需要花大量的时间做跟踪调试,验证是不是符合我们的预期,中间变量和表达式的是不是正确等等。方便的调试工具最能节省编码时间。

  • 版本管理工具:把所有的开发代码放到版本管理库,记录下来所有人对项目文件的增加、删除、修改和合并操作,误删文件这种低级失误从此再也不会出现了(经理再也不用担心我的代码了!)。同时也利于多人的团队协作开发,以及多个版本同时开发维护。所以,我们也需要一款好用的版本管理工具。

  • 代码合并和混淆工具:代码混淆工具像其他语言(Java和Dotnet等)也都会用到,混淆以后使得反编译的代码不具有可读性,从而保护了我们的劳动成果,也防止坏人反向分析我们的业务逻辑,保护了我们应用系统的安全性。代码合并工具是前端开发领域里一个比较独特的东西,常见的非脚本语言一般都没有(Java是编译后生成jar包,Dotnet是编译完就成了dll或exe文件,都不需要对源代码进行打包)。

  • 依赖管理工具:就像Java里的Maven、Dotnet里的NuGet,我们希望前端里也有一个工具可以帮我们管理项目的各种不同版本的依赖,自动下载、配置和更新。特别是项目比较大的时候,我们依赖了非常多的第三方库,这时候如果没有一个自动化的工具来管理这些依赖,每个依赖项都需要人工维护的话,很容易导致缺包、版本错误等问题,对项目本身就是一个灾难。使用依赖管理工具的另外一个好处是,项目里不需要带上各种依赖的库,他们将会在构建项目时再从远程依赖库下载,这就减少了项目源码环境的核心文件数量。

  • 单元测试工具:一直以来,前端的单元测试都是一件非常困难的事情。因为前端的JS代码常常会去操作页面的DOM元素,所以测试代码必须在浏览器环境下运行,我们的测试代码脱离了浏览器环境就无法运行。后来NodeJS的出现,把这种不可能变成了现实,特别是对浏览器里的DOM元素也可以直接操作。

  • 集成测试工具:当业务模块功能完成以后,我们希望可以自动模拟用户的输入和点击操作,模拟相关的业务功能,完成整个业务功能的自动化测试。

只要有了这样一整套工具支撑前端代码的开发,我们就可以摆脱刀耕火种的原始社会时代,进入现代社会的自动化、工业化时代!## 开发工具

本节为大家介绍最常见的11款前端开发工具。在实际项目中,这十一款神器不一定会全部都用到,大家可以根据具体的情况,适当地选择自己所需要的进行搭配。本节我们先逐一介绍下这些工具,然后使用这些工具组装一套完整而且“高大上”的前端开发环境。

All Tools

如上图所示的这11款工具中,NodeJS是其他工具的基础,其他的绝大部分工具都是围绕着NodeJS来实现的。在目前的前端领域的工具生态链里,NodeJS已经成为了整个生态环境的基石。

Sublime

Sublime

Sublime是一款功能非常强大的文本编辑器(收费软件、但是可以无限期试用)。官方网站地址为:http://www.sublimetext.com。进入官方网站首页,可以看到常用的一些功能演示视频。主要功能如下:

  • 支持多种编程语言的语法高亮;
  • 拥有优秀的代码自动完成功能;
  • 支持技术宅习惯的vim编辑模式,非常多的快捷键;
  • 支持宏,可以把操作保存下来重放;
  • 支持各种功能丰富的插件,在菜单里可以直接查看和安装插件;
  • 支持多标签页、多种布局和缩略图;
  • 支持文件导航、全屏编辑、列操作模式;
  • 多重选择,支持页面中同时有多个光标,同时编辑多个位置;
  • ……

一些非常高大上的功能:

  • 软件意外退出或突然崩溃时,不会丢失编辑内容(大家都有过记事本没保存的经历吧?);
  • 加载比较大的文件,例如几M的文件,非常流畅,不卡顿、不影响编辑。
  • HTML代码快速编码(Zen Coding)功能。比如,如果我们要生成一个样式为row的div,内部包含10个样式为col-md-12的div,只需要输入如下24个字符:div.row>div.col-md-12*10,然后使用快捷键Ctrl+E,生成出来几十倍的代码,效果如下:

Sublime

出现于2009年的Zen Coding技术,可能是广大前端程序员最喜欢的功能了。熟悉JQuery选择器语法的同学,应该能很快发挥这个神器的强大威力,将前端代码开发变成既酷又爽的体验过程。

WebStorm

WebStorm

代码编辑工具,除了轻量级的Sublime,还有重量级的WebStorm。这款JetBrains出品的代码编辑器,界面风格和使用方式跟IntelliJ IDEA完全一致,可以看做是IDEA针对Web前端开发的定制版本。使用过IDEA编辑器的同学可以快速上手使用。

当然Zen Coding、多光标编辑、vim操作、快捷键支持这些都少不了。除了常规的代码编辑器功能以外,还有一些炫酷特性:

  • 本地编辑历史功能,所有的改动都不会丢失;
  • 支持Git等版本管理工具,可以直接运行和调试;
  • 支持NodeJS和NPM等前端工具集;
  • 支持通过FTP方式部署代码到服务器环境;
  • 支持代码格式化、代码重构、代码折叠、结构浏览等功能;
  • 编写HTML、CSS的时候,可以实时检测代码在各种不同浏览器下的兼容性如何;
  • 有专门支持AngularJS开发的插件;
  • ……

WebStorm AngularJS Plugin

同样展示下在WebStorm下的Zen Coding功能,新建一个test.html文件,输入div.row>div.col-md-12*10,然后点击Tab键,效果如下:

WebStorm AngularJS Plugin

WebStorm有非常多的功能特性和使用技巧,快捷键设置等等,需要的同学可以在网上自行搜索学习。WebStorm的功能比Sublime丰富的多,当然也更消耗资源,如果大家的开发机器配置比好的话,建议使用WebStorm进行开发。

AngularJS Batarang

断点调试工具Batarang是Chrome浏览器的一个插件。Batarang的名称来源于蝙蝠侠的蝙蝠标识,它是Chrome浏览器的一个插件。当然大家也可以使用传统的断点调试Firebug,但是Batarang的优势在于它是专门针对AngularJS开发的调试器,内置了很多专门针对AngularJS的菜单和功能。

Chrome浏览器是Google公司基于Webkit内核、JavaScript V8引擎开发的浏览器,具有速度快,稳定不易奔溃,简洁、安全,广泛支持多种平台等功能特性。据StatCounter统计,2014年8月份,Chrome浏览器在中国的市场占有率以49.51%高居榜首,IE 浏览器排名第二位市场份额28%。可以说Chrome已经是目前最流行的浏览器了。

Batarang可以用如下两种方式进行安装:

第一种方式直接从Chrome中安装:在Chrome浏览器的菜单中选择“更多工具”-“扩展程序”进入扩展程序页面,点击“获取更多扩展程序”;在Chrome网上应用店页面,搜索AngularJS Batarang,找到插件后点击右上角的“免费”,然后按提示安装即可。如果第一种方式比较慢的话,可以尝试下面的第二种方式。

AngularJS Batarang Plugin

AngularJS Batarang Plugin
AngularJS Batarang Plugin

第二种方式从GitHub网站获取AngularJS Batarang发布的压缩包进行安装。首先从如下地址下载最新的zip压缩包:

https://github.com/angular/angularjs-batarang/releases

解压到本地文件夹,然后进入扩展程序页面,勾选上开发者模式,点击加载正在开发的扩展程序...,选择解压的文件夹,加载完Batarang插件后勾选上已启用即可。

AngularJS Batarang Plugin

使用方式:在打开要跟踪调试页面的Chrome浏览器里按F12,打开控制台,可以看到控制台里多一个AngularJS的标签页,此时即可使用Batarang的功能。

Git/TortoiseGit

Git是目前最流行的代码版本管理工具。跟CVS、SVN最大的不同点应该是Git有本地代码仓库和远程仓库的概念,这样我们一般情况下的的提交操作都是在本地仓库进行的,只有我们显示的执行远程同步命令,Git才会把本地仓库的代码变化同步到Git服务器上的远程仓库、或是从Git服务器上的远程仓库同步到本地仓库。

可以从官方网站下载Git的客户端:

http://git-scm.com/download/

Git

点击对应平台的图标下载安装文件,下载完成后直接运行,即可安装到系统。在命令行输入如下命令:

git --version

输出版本信息,则证明安装成功:

git version 1.9.5.msysgit.0

此时就可以用git clone从GitHub或其他Git服务器下载项目代码了。比如克隆AngularJS项目的源码到本地:

git clone https://github.com/angular/angular.js

执行完成了以后,本地的代码仓库就有了一个AngularJS项目源码的一个副本。可以修改,也可以添加文件到本地仓库,例如添加一个叫test.js的文件:

git add test.js

添加当前目录下的所有新建文件到本地仓库:

git add .

修改完了也可以提交到本地仓库:

git commit test.js -m "add a test"

提交当前目录下的所有变动过的文件:

git commit . -m "some reasons"

如果想要修改AngularJS的代码后同步到GitHub网站,可以先在GitHub上把项目fork到自己的仓库里,然后clone到本地,修改后git commit,最后再执行如下命令即可同步本地仓库到GitHub远程仓库:

git push

如果其他人也修改了这个远程仓库,可以使用如下命令同步远程仓库到本地仓库:

git pull

我们也可以使用如下命令查看本地代码仓库的未提交变动:

git status

或者使用如下命令查看代码的所有修改记录:

git log

特别地,我们可以只查看某个文件的最近几条log,例如查看test.js的最近2条修改记录:

git log -2 test.js

如果你习惯于使用GUI界面的版本管理工具,特别是有过使用TortoiseSVN的经历,则可以下载TortoiseGit使用。

可以从官方网站下载TortoiseGit:

http://download.tortoisegit.org/tgit/

TortoiseGit

安装后,在任意文件夹中点击右键,右键菜单就可以看到Git相关的操作,比如点击Git Clone...即可开始从服务器端clone项目代码。如果想要使用中文的界面菜单,可以在下载页面下载相应的中文语言包。

NodeJS

NodeJS目前对于前端开发整个生态圈的重要性,就无需累述了。大家可以从官方网站直接下载安装:

http://nodejs.org/

NodeJS

NodeJS里有个非常给力的包管理器(NodeJS Package Manager,NPM),通过NPM我们几乎可以使用整个NodeJS生态圈的所有美妙工具和框架、类库。NPM官方网址:

https://www.npmjs.com/

由于NPM现在是NodeJS自带的工具。你也可以在这个页面的左下方找到Install NPM,进入下载页面选择合适的NodeJS版本进行下载安装。安装完了NodeJS就可以直接使用NPM来管理和安装其他的库了。

NPM使用一个叫package.json的文件管理各种库的元数据和依赖(类似Java项目中maven使用的pom文件)。我们一般把这个文件放到项目源码的根目录中,并在项目提交时一并提交到npm服务器。当我们在项目源码根目录执行npm install时,NPM会分析此文件中的依赖项列表,并将它们都下载并加载到项目中。更多package.json的信息可以参见:

https://docs.npmjs.com/files/package.json

小贴士:我们每次安装依赖库都访问国外的npmjs主站可能会比较慢,幸好淘宝搭建了一个npm镜像,通过如下命令即可配置以后使用淘宝的镜像:

npm config set registry https://registry.npm.taobao.org

如果你有可用的vpn或代理服务器,则可以直接在命令行设置NPM使用的代理(其中代理服务器的ip和端口需要修改成你自己的):

set PROXY=http://localhost:8087
set HTTPS_PROXY=http://localhost:8087

NodeJS

关于NPM代表什么意思,官网https://www.npmjs.com/首页的左上角会显示各种不同的解释,点击一下就会换一种,比如Napping Panda MissionariesNever Poke MonkeysNode Package Managernom, please more等等。
这些解释还有一个专门的GitHub项目,地址为:

https://github.com/npm/npm-expansions

安装完NodeJS以后,可以执行如下命令进入基础知识学习:

npm install -g learnyounode

返回如下信息:

C:\Program Files\nodejs\learnyounode -> C:\Program Files\nodejs\node_modules\learnyounode\learnyounode.js
learnyounode@2.3.2 C:\Program Files\nodejs\node_modules\learnyounode
├── workshopper-boilerplate@0.0.1
├── duplexer@0.1.1
├── after@0.8.1
├── rimraf@2.2.8
├── through@2.3.6
├── boganipsum@0.1.0
├── hyperquest@0.2.0 (through@2.2.7)
├── chalk@0.4.0 (has-color@0.1.7, ansi-styles@1.0.0, strip-ansi@0.1.1)
├── colors-tmpl@0.1.1 (colors@0.6.2)
├── combined-stream@0.0.7 (delayed-stream@0.0.5)
├── workshopper-wrappedexec@0.1.2 (xtend@2.1.2)
├── through2@0.4.2 (xtend@2.1.2, readable-stream@1.0.33)
├── concat-stream@1.4.7 (inherits@2.0.1, typedarray@0.0.6, readable-stream@1.1.13)
├── through2-map@1.2.1 (through2@0.2.3, terminus@1.0.11)
├── workshopper-exercise@2.1.0 (tuple-stream@0.0.2, split@0.3.2, visualwidth@0.0.1, xtend@2.1.2, i18n-core@1.3.2)
├── stream-browserify@1.0.0 (inherits@2.0.1, readable-stream@1.0.33)
├── bl@0.7.0 (readable-stream@1.0.33)
└── workshopper@2.2.0 (map-async@0.1.1, xtend@3.0.0, mkdirp@0.3.5, visualwidth@0.0.1, terminal-menu@1.0.2, optimist@0
.6.1, i18n-core@1.3.2, msee@0.1.1)

接着可以执行如下命令,开始学习NodeJS:

learnyounode

NodeJS

进入学习界面后,点击键盘上的上下光标可以选择菜单,回车进入课程。我们先进入最后的choose langguage,选择中文,然后回车,即可看到界面已经变成中文:

NodeJS

选择你好,世界,点击回车,接下来就可以按照教程学习:

NodeJS

Grunt

Grunt

我们前面提到了为了保护我们的代码、同时也为了节省网络IO开销而减小JS文件和降低文件数量,需要发布前端代码时对多个JS文件进行合并压缩和混淆。当然我们也不希望每次都得手动去做这件繁琐的事儿,这时Grunt就是一个非常理想的选择。NodeJS里的Grunt加上NPM基本上相当于Java里的Maven或Gradle、SBT。

可以直接使用npm安装Grunt,在命令行下输入:

npm install grunt

返回如下信息:

grunt@0.4.5 node_modules\grunt
├── dateformat@1.0.2-1.2.3
├── which@1.0.8
├── eventemitter2@0.4.14
├── getobject@0.1.0
├── colors@0.6.2
├── rimraf@2.2.8
├── async@0.1.22
├── hooker@0.2.3
├── grunt-legacy-util@0.2.0
├── exit@0.1.2
├── lodash@0.9.2
├── underscore.string@2.2.1
├── coffee-script@1.3.3
├── iconv-lite@0.2.11
├── grunt-legacy-log@0.1.1 (underscore.string@2.3.3, lodash@2.4.1)
├── glob@3.1.21 (inherits@1.0.0, graceful-fs@1.2.3)
├── nopt@1.0.10 (abbrev@1.0.5)
├── minimatch@0.2.14 (sigmund@1.0.0, lru-cache@2.5.0)
├── findup-sync@0.1.3 (lodash@2.4.1, glob@3.2.11)
└── js-yaml@2.0.5 (esprima@1.0.4, argparse@0.1.16)

就会在当前目录的node_modules文件夹下安装grunt工具。如果加上-g参数,就可以把grunt安装到NodeJS的全局目录,所有的地方都可以使用这个工具了:

npm install -g grunt

如果加上-d参数,则同时将grunt所有依赖的库都安装上。

npm install -gd grunt

如果在当前项目里使用–save/–save-dev参数,则npm会更新更新package.json里的dependencies和devDepandencies配置:

npm install grunt -save
npm install grunt -save-dev

执行如下命令可以实现安装Grunt命令行:

npm install -g grunt-cli

返回如下信息说明安装成功:

C:\Program Files\nodejs\grunt -> C:\Program Files\nodejs\node_modules\grunt-cli\bin\grunt
grunt-cli@0.1.13 C:\Program Files\nodejs\node_modules\grunt-cli
├── resolve@0.3.1
├── nopt@1.0.10 (abbrev@1.0.5)
└── findup-sync@0.1.3 (lodash@2.4.1, glob@3.2.11)

然后可以在命令行直接使用Grunt:

grunt --version

输出如下信息:

grunt-cli v0.1.13
grunt v0.4.5

使用Grunt需要使用两个配置文件,一个是指定Grunt库的相关依赖的package.json文件,基本配置类似下面的代码:

{
  "name": "my-project-name",
  "version": "0.1.0",
  "devDependencies": {
    "grunt": "~0.4.1",
    "grunt-contrib-jshint": "~0.6.0",
    "grunt-contrib-nodeunit": "~0.2.0",
    "grunt-contrib-uglify": "~0.2.2"
  }
}

还需要一个专门的配置文件Gruntfile,这个文件可以使用Javascript或CoffeeScript实现,所以具体的文件名可以是Gruntfile.jsGruntfile.coffee。一个典型的配置文件如下所示:

module.exports = function(grunt) {

  // Project configuration.
  grunt.initConfig({
    pkg: grunt.file.readJSON('package.json'),
    uglify: {
      options: {
        banner: '/*! <%= pkg.name %> <%= grunt.template.today("yyyy-mm-dd") %> */\n'
      },
      build: {
        src: 'src/<%= pkg.name %>.js',
        dest: 'build/<%= pkg.name %>.min.js'
      }
    }
  });

  // 加载包含 "uglify" 任务的插件。
  grunt.loadNpmTasks('grunt-contrib-uglify');

  // 默认被执行的任务列表。
  grunt.registerTask('default', ['uglify']);

};

例子中加载了Grunt插件,定义了自定义任务,运行时执行压缩js源码的工作并在文件添加一句带有时间戳的注释。此外,Grunt还有很强大的编译时做代码检查的功能插件grunt JSHint,检测到文件发生变化时就执行编译压缩的功能插件grunt watch,执行JS代码测试、执行CSS编译合并等等。

Grunt这个词的意思是呼噜、咕哝,也表示魔兽争霸中的兽人步兵,孔武有力,轻松解决一切困难的任务。

还有一个说法是,来源于Grunt Work,这个词的意思是繁重无聊的重复劳动,而Grunt工具的目标就是消除这些繁琐任务,把前端程序员的创造力解放出来。

更多信息可以参考官方网站:

http://gruntjs.com/

Bower

Bower

Bower是Twitter公司开发的Web包管理工具。它能够自动安装我们项目中需要的Javascript依赖库,检测各个库里依赖的其他库,以及管理各种库的版本。

安装非常简单,执行npm安装命令即可:

npm install -g bower

使用bower安装JS库也非常简单:

# 安装jquery
bower install jquery
# 安装GitHub里库,直接可以不写https://github.com/
bower install desandro/masonry
# 也支持Git协议
bower install git://github.com/user/package.git
# 当然也可以使用JS文件的URL进行安装
bower install http://example.com/script.js

例如执行第一个命令安装jquery,输出如下信息:

bower jquery#*                  cached git://github.com/jquery/jquery.git#2.1.3
bower jquery#*                validate 2.1.3 against git://github.com/jquery/jquery.git#*
bower jquery#~2.1.3            install jquery#2.1.3

jquery#2.1.3 bower_components\jquery

这说明已经安装成功。此时在本地的bower_components文件夹下,就可以看到jquery的js文件和源代码。

如果项目里依赖的JS库比较多,则可以像Grunt一样的使用配置文件,配置文件名称叫bower.json,然后在项目目录下执行如下命令即可:

bower init

典型的bower.json文件如下所示:

{
  "name": "my-project",
  "version": "1.0.0",
  "main": "path/to/main.css",
  "ignore": [
    ".jshintrc",
    "**/*.txt"
  ],
  "dependencies": {
    "<name>": "<version>",
    "<name>": "<folder>",
    "<name>": "<package>"
  },
  "devDependencies": {
    "<test-framework-name>": "<version>"
  }
}

Bower这个词的含义是树荫、凉亭,大树底下好乘凉,有了它,什么JS的库依赖都能摆平。这个项目是由Twitter公司的F.A.TAlex MacCaw带领的团队开发的,于2012年作为Twitter开源工程的一部分。Twitter公司的logo原型是一只拉里鸟,这个项目跟鸟也自然有关系。BowerBird是园丁鸟科的一种鸟,这种鸟的雄鸟会打造一个凉亭(英文也是Bower),然后用颜色鲜艳的饰物来装饰它,用以吸引异性。所以这个项目的logo也是一个嘴里衔着一片树叶的漂亮小鸟,象征着Bower从JavaScript库的森林里带来点点滴滴的依赖库用以构建自己的体系。

更多的信息请参考官网网站:

http://bower.io/

http-server

http-server

我们一般的项目中用到的AppServer或是WebServer一般都比较重量级,我们测试一些前端展示的页面需要准备很重量级的环境不是很方便。特别是有时候我们的后端和前端是并行开发,编写前端代码的时候,后端的数据接口并没有准备好,也迫切要求我们在前端开发过程中有一个简单可用、灵活变化,可以快速的启动、方便修改、随时可以模拟后台数据的轻量级Server环境。NodeJS里的http-server模块就是这么一个轻量级的server。同其他工具一样,我们使用NPM安装:

npm install -g http-server

显示以下信息则表示安装成功:

C:\Program Files\nodejs\http-server -> C:\Program Files\nodejs\node_modules\http-server\bin\http-server
C:\Program Files\nodejs\hs -> C:\Program Files\nodejs\node_modules\http-server\bin\http-server
http-server@0.7.4 C:\Program Files\nodejs\node_modules\http-server
├── opener@1.4.0
├── colors@1.0.3
├── union@0.4.4 (qs@2.3.3)
├── portfinder@0.2.1 (mkdirp@0.0.7)
├── optimist@0.6.1 (wordwrap@0.0.2, minimist@0.0.10)
└── ecstatic@0.5.8 (mime@1.2.11, he@0.5.0, minimist@1.1.0)

此时,我们再任意的文件夹新建一个index.html文件,内容如下:

<html>
<body>
<H1>hello,http-server!</H1>
</body>
</html>

然后在此路径下命令行执行:

http-server

返回如下信息证明已经启动:

Starting up http-server, serving ./ on: http://0.0.0.0:8080
Hit CTRL-C to stop the server

在浏览器中访问http://localhost:8080,显示如下图:

http-server

如果目录中没有index.html文件,则浏览器中会列出所有的文件列表:

http-server

这个例子说明,我们可以在任意的目录执行“,使得本目录变成一个HttpServer的根目录,可以通过HTTP协议方法目录中的所有文件,很方便我们测试、调试前端代码。

Http-server是不是很酷?

跟Apache Http Server或是Microsoft IIS服务器拥有一样的功能,但是方便得多,简单得多。当然除了作为HttpServer独立运行,很多的时候我们也会直接在NodeJS代码中使用http-server模块实现更复杂的功能和逻辑,像不像Jetty这种嵌入式的HttpServer?

更多的用法和参数,详见http-server的官方网站:

https://github.com/nodeapps/http-server

Karma

Karma

Karma是一款用来执行测试用例的工具,由Pivotal Labs公司开发,在2012年开源、2013年改名为Karma,官方网站首页为:

http://karma-runner.github.io

Karma最大的特点就是支持在不同平台的多种浏览器中运行测试的JavaScript代码。这个项目的主要目标就是使前端JavaScript的测试驱动开发(Test-Driven Development,TDD)更简单、更快、更有趣。而且它也做到了这个目标,so cool!

Karma有几个突出特性:

  • 在真实的设备上运行测试用例,设备包括各种手机和平板、甚至是没有界面的PhantomJS实例;
  • 可以从命令行或IDE上远程控制整个测试流程,只需要保存一个文件,Karma就会自己运行所有的测试用例;
  • 可以直接跟Jasmine,Mocha,QUnit等测试框架集成,甚至对任何其他测试框架、你可以简单实现一个适配器集成到Karma;
  • 可以跟Grunt,Gulp等工具集成,使得在开发是方便地进行自动化测试;
  • 直接可以在类似WebStorm或Google Chrome之类的工具中方便地调试;
  • 可以跟Jenkins,Travis,Semaphore等持续集成工具集成;

对于AngularJS项目,官方推荐使用karma-ng-scenario插件和Protractor进行测试。
具体的例子,我们结合下一个测试用例编写工具Jasmine一起来看。

Karma的官方首页上用大字号的英文写到:“在AngularJS团队,我们依赖测试,所以我们一直在寻找更好的工具来改善我们的程序人生。这就是为什么我们创造了Karma,这个能满足我们一切需要的测试用例执行工具的原因”。

Karma这个单词的意思是因果报应、因缘。所谓有其因必有其,这是不是恰恰跟测试的内涵是一致的呢?

关于这个项目名字的来历也很有意思,项目的创立者Vojta Jina最开始的时候根据“神奇测试工具(Testing Spectacular)”的寓意,把这两个词合并成一个就成了项目名称Testacular。开源以后用的人多了,就有人发现这个词跟另一个非常有争议的词“睾丸(testicular)”几乎一样,这时候就有人建议项目更改一个名字。盐湖城的网友Ryan Florence在2013年3月5号在项目的GitHub官方提了一个建议,很快得到了非常多的人参与讨论,大部分人支持改名。到了3月8日国际妇女节这天,Jina终于决定项目改名为Karma

Jasmine

Jasmine

Jasmine提供了一套类似于Java里的JUnit或Google Truth的语法,使用行为驱动方式来编写JavaScript单元测试代码(Behavior-Driven JavaScript)。

Jasmine四个核心概念:分组、用例、期望、匹配,分别对应Jasmine的四种函数:

  • describe(string,function):这个函数表示分组,也就是一组测试用例。类似于JUnit里的一个TestSuite。
  • it(string,function):这个函数表示测试用例。类似于JUnit里的TestCase。
  • expect(expression):表示期望expression这个表达式具有某个值或者具有某种行为。expectto***结合成expect(期望值).toXXX(实际值),类似JUnit里的Assert.assertXXX(期望值,实际值)
  • to***(arg):这个函数表示匹配。

典型的测试用例代码如下:

describe("A suite", function() {
  it("contains spec with an expectation", function() {
    expect(true).toBe(true);
  });
});

describe("A suite is just a function", function() {
  var a;

  it("and so is a spec", function() {
    a = true;

    expect(a).toBe(true);
  });
});

在浏览器里运行,结果如下:

2 specs, 0 failures
A suite
contains spec with an expectation
A suite is just a function
and so is a spec

更多的信息可以参见Jasmine的官方网站:

http://jasmine.github.io/

Jasmine的含义是茉莉花,它让我们可以像茉莉一样优雅地编写测试代码。

这个项目诞生于2008年的感恩节,Pivotal Labs公司当时需要一款不依赖于DOM和请求-响应周期的JavaScript测试框架,但是市面上没有可用的,于是Davis W. Frank决定自己实现。他当时在旧金山的家里开始做这个测试框架,后院里开满了前任房子主人留下的茉莉花(英文名Jasmine)。在某个一瞬间,Frank脑子里涌现了一个很久之前就有的思想火花,从最简洁的JavaScript测试框架这几个词出发,就可以联想到茉莉花:JavaScript Minimal Testing -> JS Minimal Test -> JS Min Test -> Jasmine。这样,这个项目就诞生了。

Protractor

Protractor

Protractor是一款端对端的集成测试工具,专门为AngularJS应用定制的自动化测试工具(End to End Testing for AngularJS)。

Proctactor的原理是利用Web自动化测试框架Selenium的WebDriverJS技术,可以借助于NodeJS直接调用浏览器(IE、FF、Chrome)的接口。Jasmine是用来编写测试,Karma是用来执行测试,Protractor用来模拟用户操作行为、自动测试。

完整的例子,可以从Github clone到本地查看:

git clone http://juliemr.github.io/protractor-demo

克隆protractor-demo代码以后,可以看到一个典型的Web自动测试代码如下:

// test/spec.js
describe('angularjs homepage', function() {
    it('should add numbers', function() {
    element(by.model('first')).sendKeys(4);
    element(by.model('second')).sendKeys(5);

    element(by.id('gobutton')).click();

    expect(element(by.binding('latest')).getText()).
        toEqual('9');
  });
});

例子里先打开一个浏览器,运行示例网页,然后自动在两个文本框分别模拟输入4和5,然后模拟点击一下按钮,最后判断输出结果文本是不是9。怎么样,很简单吧。

执行测试也很简单,在项目目录打开两个命令行,第一个命令行执行下面两个命令:

npm install
npm start

另一个命令行,执行:

npm test

效果如下:

Protractor

Protractor

最后可以看到测试结果:

Finished in 11.587 seconds
3 tests, 5 assertions, 0 failures

更多信息参见官方网站地址:

https://github.com/angular/protractor

详细的使用文档参见:

https://github.com/angular/protractor/tree/master/docs

WebDriverJs可以参见:

https://code.google.com/p/selenium/wiki/WebDriverJs

Protractor这个英文单词的含义是量角器,用于精确的度量我们的AngularJS项目。而且官方还有一个说法:量角器(Protractor)是用来测量角度(Angles)的,而本项目Protractor是用来测试AngularJS的(注意AnglesAngularJS比较相似)。

项目结构

本章的最后我们来看一下整合好的前端开发环境结构。一个典型的目录如下图所示:

http-server

常用的目录项,整理如下:

|-.git          //git使用的文件夹
|-package.json  //npm配置文件
|-bower.json        //bower配置文件
|-Gruntfile.js  //Grunt配置文件
|-app           //web应用的前端代码
    |-bower_components  //bower依赖库,不需要加入到git仓库
    |-js
    |-img
    |-css
    |- ... ...
|-node_modules  //npm依赖库,不需要加入到git仓库
|-scripts       //项目常用的shell脚本
|-test          //前端JavaScript test代码
    |-protractor-conf.js        //protractor配置文件
    |-karma.conf.js         //karma配置文件
    |-e2e                   //交互场景测试代码
    |-unit                  //单元测试代码

具体的项目里,可以根据自己的需求选择合适的几款技术框架和开发工具,不需要全部的东西都用上。

  • 16
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 10
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 10
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

kimmking

赠人玫瑰手有余香

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值