單元測試簡介:https://segmentfault.com/a/1190000009737186
單元測試-Jasmine:https://segmentfault.com/a/1190000009737204
angular2單元測試:https://segmentfault.com/a/1190000009769787#articleHeader1
概念簡介
Jasmine
Jasmine測試框架提供了編寫測試腳本的工具集,而且非常優秀的語義化,讓測試代碼看起來像是在讀一段話。
describe,beforeEach,it,expect等方法,利用這些方法可以定義單元測試如何執行,單元測試的結果和預期。
官方文檔:https://jasmine.github.io/api/edge/global.html#expect
Karma
有Jasmine測試腳本,還需要Karma來幫忙管理這些腳本,以便於在瀏覽器中運行,可以理解Karma為運行這些測試腳本的容器。
需要在根目錄創建 karma.conf.js 文件,這相當於一些約定。文件是為了告知karma需要啟用哪些插件、加載哪些測試腳本、需要哪些測試瀏覽器環境、測試報告通知方式、日志等等。
官方文檔:https://karma-runner.github.io/1.0/config/configuration-file.html
Angular測試工具集
testded
testded是angular提供用於單元測試的主要工具方法。為單元測試配置和初始化環境,提供創建組件和服務的方法。
還有spy和一些異步支持
結合Jasmine和Angular測試工具集編寫單元測試案例
Jasmine單元測試的基礎概念
Jasmine中的單元測試有幾個概念:test suit、Specs、Expectations
test suit 測試套件
可以理解為一組單元測試用例的集合。Jasmine用describe函數來表示
Specs 測試案例
一個單元測試用例,Jasmine使用函數it來表示
Expectations 期望值
一個單元測試用例執行后,對執行結果的期待,Jasmine使用函數expect來表示
Jasmine單元測試常用方法
Matchers:對期待值進行判斷,toBeTruthy,toBeNull這種,也可以自己實現Matcher
Setup 與 Teardown:在測試套件中,一些重復的代碼可以放在setup和teardown中。setup(對應beforeEach)為每一個單元測試案例執行之前會執行,Teardown(對應afterEach)為每一個單元測試案例執行之后會執行,
數據共享:在describe 來定義相應的變量,這樣每個 it 內部可以共享它們
spy: 文檔翻譯:https://blog.csdn.net/GuoJiangweigege/article/details/52130589 並參照:https://www.cnblogs.com/laixiangran/p/5060922.html
spyOn(object, "methodNam");//在object對象上添加methodNam,當調用object對象上的方法,為模擬調用,不會執行methodNam方法的代碼。spyOn寫在beforEach或者it中,每一個測試案例執行完之后,被銷毀。
spyOn(object, "methodNam").and.callThrough();//methodNam方法的代碼會被執行
spyOn(object, "methodNam").and.callFake(fn);//methodNam方法會被fn替代,執行fn
spyOn(object, "methodNam").and.returnValue(value);//methodNam的返回值為value
Angular工具集
TestBed
如官方所說,是angular單元測試最主要的api。個人理解是一組單元測試的測試context,按配置生成模塊、組件,然后提供這些模塊或者組件用於單元測試。
1 TestBed創建模塊:TestBed.configureTestingModule
構建一個angular模塊,並返回,接受參數用於配置模塊,和@NgModule的配置無差別。
beforeEach(() => {
TestBed.configureTestingModule({
imports: [HttpModule],
declarations: [TestComponent]
});
});
2 TestBed創建組件:TestBed.createComponent
創建組件,返回一個fixture。fixture 包括組件實例、變更監測以及DOM相關的屬性,它是用來寫單元測試的核心。
1 @Component({ 2 template: `<trade-view [id]="id" (close)="_close()"></trade-view>` 3 }) 4 class TestComponent { 5 id: number = 0; 6 _close() { } 7 } 8 9 beforeEach(() => { 10 TestBed.configureTestingModule({ 11 imports: [HttpModule], 12 declarations: [TestComponent] 13 }); 14 fixture = TestBed.createComponent(TestComponent); 15 component = fixture.componentInstance; //組件實例 16 el = fixture.nativeElement; //組件原生元素17 });
3 異步beforeach(具體可參考angular官方文檔 測試-調用compileComponents())
如果一個組件使用了templateUrl和styleUrls獲取模板或者模板樣式,這是一個異步的過程,那么需要使用異步beforeach創建組件,否則會報錯無法編譯組件。
如下是沒有使用異步beforeach創建組件:
1 beforeEach(() => { 2 TestBed.configureTestingModule({ 3 declarations: [ BannerComponent ], 4 }); 5 fixture = TestBed.createComponent(BannerComponent); 6 });
如果這個組件沒有使用templateUrl或styleUrls,那么不會有任何問題,因為createComponet就會執行組件的編譯,然后再創建組件。但如果使用了templateUrl或styleUrls,則獲取url地址文件的過程是異步的,在createComponent時如果沒有返回地址,那么執行編譯就會報錯。這時,用異步的beforeach來解決這個問題。
1 beforeEach(async(() => { //使用angular提供的輔助異步函數 2 TestBed.configureTestingModule({ 3 declarations: [ BannerComponent ], 4 }) 5 .compileComponents() 6 .then(() => { 7 fixture = TestBed.createComponent(BannerComponent); 8 component = fixture.componentInstance; 9 h1 = fixture.nativeElement.querySelector('h1'); 10 }); 11 }));