以下是我假定那些少少或压根没写单元测试的人预备的,因而,会白话诠释诸多观点性问题,同时会连系 Jasmine 与之对应的要领举行解说。
一、观点
Test Suite
测试套件,哪怕一个简朴的类,也会有多少的测试用例,因而将这些测试用例集合在一个分类下就叫Test Suite。
而在 Jasmine 就是运用 describe
全局函数来示意,它的第一个字符串参数用来示意Suite的称号或题目,第二个要领参数就是完成Suite代码了。
describe('test suite name', () => {
});
Specs
一个Specs相当于一个测试用例,也就是我们完成测试详细代码体。
Jasmine 就是运用 it
全局函数来示意,和 describe
相似,字符串和要领两个参数。
而每一个 Spec 内包含多个 expectation 来测试须要测试的代码,只需任何一个 expectation 效果为 false
就示意该测试用例为失利状况。
describe('demo test', () => {
const VALUE = true;
it('should be true', () => {
expect(VALUE).toBe(VALUE);
})
});
Expectations
断言,运用 expect
全局函数来示意,只吸收一个代表要测试的现实值,而且须要与 Matcher 代表期望值。
二、常常使用要领
Matchers
断言婚配操纵,在现实值与期望值之间举行比较,并将效果关照Jasmine,终究Jasmine会推断此 Spec 胜利照样失利。
Jasmine 供应非常丰富的API,一些常常使用的Matchers:
-
toBe()
同等===
- toNotBe() 同等
!==
- toBeDefined() 同等
!== undefined
- toBeUndefined() 同等
=== undefined
- toBeNull() 同等
=== null
- toBeTruthy() 同等
!!obj
- toBeFalsy() 同等
!obj
- toBeLessThan() 同等
<
- toBeGreaterThan() 同等
>
- toEqual() 相当于
==
- toNotEqual() 相当于
!=
- toContain() 相当于
indexOf
- toBeCloseTo() 数值比较时定义精度,先四舍五入后再比较。
- toHaveBeenCalled() 搜检function是不是被挪用过
- toHaveBeenCalledWith() 搜检传入参数是不是被作为参数挪用过
- toMatch() 同等
new RegExp().test()
- toNotMatch() 同等
!new RegExp().test()
- toThrow() 搜检function是不是会抛出一个毛病
而这些API之前用 not
来示意负值的推断。
expect(true).not.toBe(false);
这些Matchers险些能够满足我们一样平常需求,固然你也能够定制本身的Matcher来完成特别需求。
Setup 与 Teardown
一份干将的测试代码很主要,因而我们能够将这些反复的 setup 与 teardown 代码,放在与之相对应的 beforeEach
与 afterEach
全局函数内里。
beforeEach
示意每一个 Spec 实行之前,反之。
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
来定义响应的变量,如许每一个 it
内部能够同享它们。
固然,每一个 Spec 的实行周时期也会伴随着一个空的 this
对象,直至 Spec 实行完毕后被清空,应用 this
也能够做数据同享。
嵌套代码
有时刻当我们对某个组件举行测试时,而这个组件会有差别状况来展现差别的效果,这个时刻假如只用一个 describe
会显得不过文雅。
因而,嵌套 describe
,会让测试代码、测试报告看起来更美丽。
describe('AppComponent', () => {
describe('Show User', () => {
it('should be show panel.', () => {});
it('should be show avatar.', () => {});
});
describe('Hidden User', () => {
it('should be hidden panel.', () => {});
});
});
跳过测试代码块
需求老是三心二意的,但十分困难写好的测试代码,岂非要删除吗?非也……
Suites 和 Specs 离别能够用 xdescribe
和 xit
全局函数来跳过这些测试代码块。
三、合营Angular东西集
Spy
Angular的自定义事宜实在太广泛了,但为了测试这些自定义事宜,因而监控事宜是不是正常被挪用是非常主要。幸亏,Spy
能够用于监测函数是不是被挪用,这简直就是我们的好同伴。
以下示例临时不必剖析,临时体验一下:
describe('AppComponent', () => {
let fixture: ComponentFixture<TestComponent>;
let context: TestComponent;
beforeEach(() => {
TestBed.configureTestingModule({
declarations: [TestComponent]
});
fixture = TestBed.createComponent(TestComponent);
context = fixture.componentInstance;
// 监听onSelected要领
spyOn(context, 'onSelected');
fixture.detectChanges();
});
it('should be called [selected] event.', () => {
// 触发selected操纵
// 断言是不是被挪用过
expect(context.onSelected).toHaveBeenCalled();
});
});
异步支撑
起首,这里的异步是指带有 Observable 或 Promise 的异步行动,因而关于组件在挪用某个 Service 来异步猎取数据时的测试状况。
假定我们的待测试组件代码:
export class AppComponent {
constructor(private _user: UserService) {}
query() {
this._user.quer().subscribe(() => {});
}
}
async
async
无任何参数与返回值,一切包裹代码块里的测试代码,能够经由过程挪用 whenStable()
让一切待处理异步行动都完成后再举行回调;末了,再举行断言操纵。
it('should be get user list (async)', async(() => {
// call component.query();
fixture.whenStable().then(() => {
fixture.detectChanges();
expect(true).toBe(true);
});
}));
fakeAsync
假如说 async
还须要回调才举行断点让你受不了的话,那末 fakeAsync
能够处理这一点。
it('should be get user list (async)', fakeAsync(() => {
// call component.query();
tick();
fixture.detectChanges();
expect(true).toBe(true);
}));
这里只是将回调换成 tick()
,怎样,是不是是很酷。
Jasmine自带异步
如前面所说的异步是指带有 Observable 或 Promise 的异步行动,而有时刻我们有些东西是依靠 setTimeout
或许多是须要外部定阅效果今后才触发时怎么办呢?
能够运用 done()
要领。
it('async demo', (done: () => void) => {
context.show().subscribe(res => {
expect(true).toBe(true);
done();
});
el.querySelected('xxx').click();
});
四、结论
本章险些一切的内容在Angular单元测试常常运用到的东西;特别是异步部份,三种差别异步体式格局并不是共存的,而是须要依据详细营业而采纳。不然,你会发明真TM难写单元测试。毕竟这是一个异步的天下。
自此,我们算是为Angular写单元测试打下了基本。后续,将不会再对这类基本举行诠释。
那末下一篇,我们将引见Component、Directive、Pipe 以及Service单元测试。
happy coding!