Angualr單元測試
Angular自己的單元測試工具:Karma + Jasmine
- Karma:是自動化測試管理工具,可以監(jiān)控文件,喚起關(guān)閉瀏覽器自動執(zhí)行測試。
- Jasmine:用來編寫JavaScript測試的框架。
概念
Test Suite
- 作用:將若干測試用例集合在一個分類下就叫測試套件
- 用
describe全局函數(shù)來表示,- 它的第一個字符串參數(shù),用來表示Suite的名稱或標(biāo)題
- 第二個方法參數(shù)就是實現(xiàn)Suite代碼了
describe('test suite name', () => {
});
Specs
- 作用:一個Specs相當(dāng)于一個測試用例
- 用
it全局函數(shù)來表示,和describe類似,字符串和方法兩個參數(shù)。
每個測試用例包括多個exception來測試需要測試的代碼,只要任何一個斷言的結(jié)果為false就表示該測試用例為失敗狀態(tài)。
Expectations
斷言,使用expect全局函數(shù)來表示,只接受一個代表要測試的實際值,并且需要與Matcher代表期望值
常用方法
Matches
斷言匹配操作,在實際值與期望值之間進行比較,并將結(jié)果通知Jasmine,最終Jasmine會判斷此用例成功還是失敗。
常用Matchers
- toBe(): === 基本類型判斷
- toNotBe(): !==
- toBeDefined():!== undefined
- toBeUndefined(): === undefined
- toBeNull(): === null
- toBeTruthy(): !!obj 判斷是否能轉(zhuǎn)換成bool型,判斷是否是true
- toBeFalsy(): !obj
- toBeLessThan(): <
- toBeGreaterThan(): >
- toEqual(): 有兩種用法,1. 對于基本的類型,相當(dāng)于toBe(); 2. 還可以用來判斷對象;
- toNotEqual():
- toContain() indexOf 判斷集合是否包含(可以是普通類型,可以是對象)
- toHaveBeenCalled(): 檢查function是否被調(diào)用過
- toHaveBeenCalledWith(): 檢查傳入?yún)?shù)是否被作為參數(shù)調(diào)用過
- toMatch(): new RegExp().text() 使用正則表達式判斷
- ToNotMatch(): 等同!new RegExp().text()
- toThrow(): 檢查function是否會拋出一個錯誤
- toBeCloseTo: 判斷數(shù)字
這些API之前可以用not來表示負(fù)值的判斷
Setup與Teardown
將重復(fù)的setup與teardown代碼,放在與之相對應(yīng)的beforEach與afterEach全局函數(shù)里面
describe('demo test', () => {
let val: number = 0;
beforeEach(() => {
val = 1;
});
it('should be true', () => {
expect(val).toBe(1);
});
it('should be false', () => {
expect(val).not.toBe(0);
});
});
嵌套代碼
describe可以相互嵌套
跳過測試代碼
xdescribe xit
配合Angualr工具集
Spy
為了測試自定義事件是否正常被調(diào)用,是非常重要的。Spy可以用來監(jiān)測函數(shù)是否被調(diào)用,這簡直就是我們的好伙伴。
describe('AppComponent', () => {
let fixture: ComponentFixture<TestComponent>;
let context: TestComponent;
beforeEach(() => {
TestBed.configureTestingModule({
declarations: [TestComponent]
});
fixture = TestBed.createComponent(TestComponent);
context = fixture.componentInstance;
// 監(jiān)聽onSelected方法
spyOn(context, 'onSelected');
fixture.detectChanges();
});
it('should be called [selected] event.', () => {
// 觸發(fā)selected操作
// 斷言是否被調(diào)用過
expect(context.onSelected).toHaveBeenCalled();
});
});
Spy用來追蹤函數(shù)的調(diào)用歷史信息(是否被調(diào)用,調(diào)用參數(shù)列表,被請求次數(shù)等)。Spy僅存在于定義它的describe和it方法塊中,并且每次在測試用例執(zhí)行完后被銷毀
spy常用
and.callThrough()在使用spy的同時也會執(zhí)行實際的代碼。and.returnValue()由于spy是模擬函數(shù)的調(diào)用,因此我們也可以強制指定函數(shù)的返回值。-
and.callFake()和returnValue相似,callFake則更進一步,直接通過指定一個假的自定義函數(shù)來執(zhí)行。比returnValue更靈活,我們可以任意捏造一個函數(shù)來達到我們的測試要求spyOn(foo, "getBar").and.callFake(function() { return 1001; }); and.thorwErrow模擬異常的拋出;and.stub重置spy
其他追蹤屬性
calls: 對于被spy的函數(shù)的調(diào)用,都可以在calls屬性中跟蹤。
-
.calls.any():被Spy的函數(shù)一旦被調(diào)用過,則返回true,否則為false -
.calls.count():返回被Spy的函數(shù)的被調(diào)用次數(shù) -
.calls.argsFor(index):返回被spy的函數(shù)的調(diào)用參數(shù),以index來指定參數(shù) -
.calls.allArgs:返回被spy的函數(shù)的所有調(diào)用參數(shù); -
.callls.all(): 返回calls的上下文,將返回當(dāng)前calls的整個實例數(shù)據(jù); -
.calls.mostRecent():返回calls中追蹤的最近一次的請求數(shù)據(jù); -
.calls.first():返回calls中追蹤的第一次請求的數(shù)據(jù); -
.object: 當(dāng)調(diào)用all(),mostRecent(),first()方法時,返回對象的object屬性返回的是當(dāng)前上下文對象 -
.calls.reset(): 重置spy的所有追蹤數(shù)據(jù);
createSpy
createSpyObj
異步支持
首先,這里的異步是指帶有Observable或promise的異步行為,因此對于組件在調(diào)用某個Service來異步獲取數(shù)據(jù)的時候測試狀態(tài)
async
async無任何參數(shù)與返回值,所有包裹在代碼塊里的測試代碼,可以通過調(diào)用whenStable()讓所有異步行為都完成后再進行回調(diào):最后,再進行斷言操作。
it('should be get user list (async)', async(() => {
// call component.query();
fixture.whenStable().then(() => {
fixture.detectChanges();
expect(true).toBe(true);
});
}));
fakeAsync
將回調(diào)換成tick()
it('should be get user list (async)', fakeAsync(() => {
// call component.query();
tick();
fixture.detectChanges();
expect(true).toBe(true);
}));
Jasmine自帶異步
- 前面的異步是指Observable或Promise的異步行為
- setTimeout或者可能是需要外部訂閱結(jié)果以后才能觸發(fā)done()方法
it('async demo', (done: () => void) => {
context.show().subscribe(res => {
expect(true).toBe(true);
done();
});
el.querySelected('xxx').click();
});