前端進階-編寫測試程式碼
Gulp
Gulp 是基於 node.js
的一個前端自動化構建工具
,開發這可以使用它構建自動化工作流程(前端整合開發環境)。 使用 gulp 你可以簡化工作量,讓你把重點放在功能的開發上,從而提高你的開發效率和工作質量。
安裝 Gulp
在安裝 gulp 之前,需要先安裝 Node.js
和 NPM
。我們可以通過訪問 Nodes官網 並下載最新版的 NodeJS,來下載和安裝 NodeJS 和 NPM。然後安裝 Gulp。
每個 Gulp 專案都以一個 Gulp 檔案開始,此檔案位於專案的根目錄中 gulpfile.js
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,包括非同步測試全部通過。