Gulp
Gulp 是基于 node.js
的一个前端自动化构建工具
,开发这可以使用它构建自动化工作流程(前端集成开发环境)。 使用 gulp 你可以简化工作量,让你把重点放在功能的开发上,从而提高你的开发效率和工作质量。
安装 Gulp
在安装 gulp 之前,需要先安装 Node.js
和 NPM
。我们可以通过访问 Nodes官网 并下载最新版的 NodeJS,来下载和安装 NodeJS 和 NPM。然后安装 Gulp。
每个 Gulp 项目都以一个 Gulp 文件开始,此文件位于项目的根目录中 gulpfile.js
,并规定你在运行 Gulp 时应执行的所有任务。由于 Gulp 文件本质上是一个 node.js 的脚本, 因此我们首先需要将 Gulp 作为依赖项,然后设置一个默认的任务。
var gulp = require('gulp');
gulp.task('default', function() {
console.log("Hello, Gulp!");
});
Grunt 任务和 Gulp 流
Sass
Sass 是一款强化 CSS 的辅助工具,它在 CSS 语法的基础上增加了变量 (variables)、嵌套 (nested rules)、混合 (mixins)、导入 (inline imports) 等高级功能,这些拓展令 CSS 更加强大与优雅。
当我们在 Sass 中编写样式表时,可以摆脱很多 CSS 的烦恼,并将其编译为纯 CSS。不要手动为每个浏览器设置 CSS 属性,使用自动前缀完成自动设置。
Jasmine
测试各类同步及异步功能,JavaScript 没有内置测试模块,我们需要使用库来获取此类功能。Jasmine 2.2
<!--引入 jasmine 库-->
<script src="lib/jasmine-2.2.0/jasmine.js"></script>
<script src="lib/jasmine-2.2.0/jasmine-html.js"></script>
<script src="lib/jasmine-2.2.0/boot.js"></script>
<!--引入源文件(应用代码)-->
<script src="src/Player.js"></script>
<script src="src/Song.js"></script>
<!--规格说明(测试文件)-->
<script src="spec/SpecHelper.js"></script>
<script src="spec/PlayerSpec.js"></script>
describe
是用于内容组织的工具,与缩进的作用类似。 describe
和 it
函数的使用创造了用于组织信息的提纲。it
用于指明程序规格(spec),它是封装测试代码的容器,帮助明确程序具体特性。如果所有 spec 内容返回 true 则该 spec 通过,其中任何一项出现问题都会造成测试失败。it
定义了这一测试的边界,describe
确定了一套测试内容,由一组相关 spec 组成。这套测例定名为 Player 表示其内容都与播放器相关。
// describe 函数-调用标记为黑色
describe("Player", function() {
var player;
var song;
beforeEach(function() {
palyer = new Player();
song = new Song();
});
it("should be able to play a Song", function() {
player.paly(song);
// expect 函数,后面跟一个匹配器-调用标记为绿色
expect(player.currentlyPlayingSong).toEqual(song);
// ...
expect(player).toBePlaying(song);
});
// ...
})
不同的组织测试的方法并没有对错之分,它取决于个人喜好。
编写测试
expect(add(0.1, 0.2)).toBe(0.3);
// 其运行效果如下
add(0.1, 0.2) === 0.3 // 表达式返回 true 测试通过
// 如果想对结果取反,在匹配器前加 not
expect(add(0.1, 0.2).not.tobe(0.1));
每个测试都是从 expect 调用开始,可以把它视为测试的出发点,开启了测试流程。expect 函数接收一个通常称为 actual 的单变量实例,add(0.1, 0.2)
是我们的测试对象。接下来告诉测试框架要对结果进行怎样的比较,比较函数又称为匹配器(matcher),是跟在 expect 之后的方法。Jasmine 有大量匹配器可用,也可以自定义它们。toBe
在语义上表示严格等于,最后我们把期望值传到匹配器。
红绿重构(refactor)周期
先写出测试,开始时候没有进行实现,所有测试点均失败。之后开始写代码以通过测试,测试保证你能安全地进行代码重构,为系统添加新特性。地址本示例如下:
先创建两个文件 AddressBookSpec.js
和 AddressBook.js
。然后更新 html 来运行它们:
<!--引入 jasmine 库-->
<script src="lib/jasmine-2.2.0/jasmine.js"></script>
<script src="lib/jasmine-2.2.0/jasmine-html.js"></script>
<script src="lib/jasmine-2.2.0/boot.js"></script>
<!--引入源文件(应用代码)-->
<script src="src/AddressBook.js"></script>
<!--规格说明(测试文件)-->
<script src="spec/AddressBookSpec.js"></script>
用 describe
建立 AddressBook 测试组,在其中用 it 添加内容要求应用能够添加联系人,采用面向对象方法处理这个问题,新建一个 AddressBook对象,向其中加入联系人,需要应用中有 addContact 方法,向方法中传入对象作为参数,下一步是确定合适的方法,检测联系人信息是否成功加入。如果获得地址本的第一个联系人应该与刚加入的联系人相同。
describe("Address Book", function() {
it("should be able to add a contact", function() {
var addressBook = new AddressBook(),
thisContact = new Contact();
addressBook.addContact(thisContact);
expect(addressBook.getContact(0)).tobe(thisContact);
});
});
function AddressBook() {
this.contacts = [];
}
AddressBook.prototype.addContact = function(contact) {
this.contacts.push(contact);
}
AddressBook.prototype.getContact = function(index) {
return this.contacts[index];
}
移除冗余代码
describe("Address Book", function() {
it("should be able to add a contact", function() {
var addressBook = new AddressBook(),
thisContact = new Contact();
addressBook.addContact(thisContact);
expect(addressBook.getContact(0)).tobe(thisContact);
});
it("should be able to delete a contact", function() {
var addressBook = new AddressBook(),
thisContact = new Contact();
addressBook.addContact(thisContact);
addressBook.deleteContact(0);
expect(addressBook.getContact(0)).not.toBeDefined();
});
});
上述代码中,我们发现一份冗余代码,在每份规格说明中都要重设 Contact 和 AddressBook。一方面这让我们的代码耦合度很低,另一方面我们在低效手动操作。Jasmine 提供了一个函数帮助我们在每个测例前运行特定代码,函数名为 beforeEach
var addressBook,
thisContact;
beforeEach(function() {
addressBook = new AddressBook(),
thisContact = new Contact();
});
测试异步代码
我们需要在函数结束时传递必要信息。
AddressBook.prototype.getInitialContacts = function(cb) {
var self = this;
setTimeOut(function() {
self.initialComplete = true;
if (cb) {
return cb();
}
}, 3);
}
在函数运行结束后,可以看到构造函数中将初值设置为 false。
describe("Async Address Book", function() {
it("should grab initial contacts", function() {
var addressBook = new AddressBook();
address.getInitialContacts();
expect(addressBook.initialComplete).toBe(true);
});
});
对异步函数的正确测试
describe("Async Address Book", function() {
var addressBook = new AddressBook();
beforeEach(function(done) {
addressBook.getInitialContacts(function() {
done();
});
});
if("should grab initial contacts", function(done) {
expect(addressBook.initialComplete).toBe(true);
done();
});
});
加上 beforeEach 函数,在异步函数回调内容中加入 done(),它会通知测试框架。把 done 作为参数传入规格说明,测试结束再调用 done,包括异步测试全部通过。