在上一篇文章中,我们介绍了 Angular 单元测试的基础知识,本文开始介绍如何对 Angular 的主要元件进行单元测试。
测试组件
我们在使用 Angular CLI 创建项目时,会自动为 AppComponent
创建一个单元测试文件 app.component.spec.ts
. 单元测试文件的名字以 .spec.ts
结尾,是一种约定,并且与被测试组件位于同一个路径中。
接下来,我们就对 app.component.spec.ts
进行研究,初步学习如何测试一个组件。 app.component.spec.ts
文件内容如下:
import { TestBed } from '@angular/core/testing’;
import { AppComponent } from './app.component’;
describe('AppComponent', () => {
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [
AppComponent
],
}).compileComponents();
});
it('should create the app', () => {
const fixture = TestBed.createComponent(AppComponent);
const app = fixture.componentInstance;
expect(app).toBeTruthy();
});
it(`should have as title 'my-app-unittest'`, () => {
const fixture = TestBed.createComponent(AppComponent);
const app = fixture.componentInstance;
expect(app.title).toEqual('my-app-unittest’);
});
it('should render title', () => {
const fixture = TestBed.createComponent(AppComponent);
fixture.detectChanges();
const compiled = fixture.nativeElement;
expect(compiled.querySelector('.content span').textContent).toContain('my-app-unittest app is running!’);
});
});
beforeEach
在文件的开头,是一个 beforeEach
初始化函数,完成测试前的准备工作。在 beforeEach
方法中,调用了 TestBed
类的 configureTestingModule
方法配置组件所在的模块。configureTestingModule
方法接收一个对象参数,而对象参数的值与模块的 @NgModule
装饰器的值相同。在这里,我们传入的是 declarations
数组,包含了 AppComponent
组件。完成模块配置后,调用 compileComponents
完成测试模块的构建。一旦构建成功,AppComponent
组件就属于该测试模块了。
createComponent
it('should create the app', () => {
const fixture = TestBed.createComponent(AppComponent);
const app = fixture.componentInstance;
expect(app).toBeTruthy();
});
在第一个单元测试用例中,使用 createComponent
方法创建了一个 AppComponent
组件装置类的对象。该对象是一个 ComponentFixture
类的实例,泛型的类型值是 AppComponent
.
ComponentFixture
类专门用于组件的调试和测试,定义如下:
class ComponentFixture<T> {
constructor(componentRef: ComponentRef<T>, ngZone: NgZone, _autoDetect: boolean)
debugElement: DebugElement
componentInstance: T
nativeElement: any
elementRef: ElementRef
changeDetectorRef: ChangeDetectorRef
componentRef: ComponentRef<T>
ngZone: NgZone | null
detectChanges(checkNoChanges: boolean = true): void
checkNoChanges(): void
autoDetectChanges(autoDetect: boolean = true)
isStable(): boolean
whenStable(): Promise<any>
whenRenderingDone(): Promise<any>
destroy(): void
}
在组件装置类的对象创建成功后,可以通过 componentInstance
属性,获得 AppComponent
组件类的实例。
最后,我们使用 toBeTruthy
匹配函数,验证 AppComponent
实例是否有效。
组件类属性
it(`should have as title 'my-app-unittest'`, () => {
const fixture = TestBed.createComponent(AppComponent);
const app = fixture.componentInstance;
expect(app.title).toEqual('my-app-unittest’);
});
在第二个单元测试用例中,对应用对标题属性的值进行了验证。因为我们已经获得了 AppComponent
实例,就可以对他的公共属性和方法进行测试。在单元测试用例中,我们使用 toEqual
方法验证 title
属性对值。
DOM 元素属性
it('should render title', () => {
const fixture = TestBed.createComponent(AppComponent);
fixture.detectChanges();
const compiled = fixture.nativeElement;
expect(compiled.querySelector('.content span').textContent).toContain('my-app-unittest app is running!’);
});
在第三个单元测试用例中,对页面上渲染的文字进行了验证。因为组件不只包含类文件,还包含模板文件,所以也需要对类和模板对交互,或者说绑定关系,进行测试,才能保证测试更充分。
我们先调用了 ComponentFixture
类的 detectChanges
方法,目的是触发组件的变化检测机制,强制更新绑定的数据。然后,再使用组件的 nativeElement
属性,查找绑定数据的 DOM 元素,最后,验证 DOM 元素的 textContent
是否与绑定的数据相同。
运行单元测试
在项目所在的路径下,打开一个命令行,运行测试命令:
ng test
你会看到测试引擎开始执行单元测试用例,并打开一个浏览器,展示测试结果。
测试结果
网友评论