Angular 单元测试
什么是单元测试?
隔离程序的每个部件,在隔离环境中运行测试用例。
在单元测试中,所写的测试需要事先提供既定的输入值与相应的逻辑单元,检测输出结果,确定它是否与我们的预期结果匹配。
建立环境
Angular 官方提供的测试工具是 Jasmine 和 Karma。
Angular CLI 会下载并安装试用 Jasmine 测试框架 测试 Angular 应用时所需的一切。
使用CLI创建的项目是可以立即用于测试的,运行CLI命令 ng test
即可。ng test
命令在监视模式下构建应用,并启动 karma 测试运行器
如果要指定执行某个目录或者文件中的测试用例可以使用命令 ng test --include='**/unit/test.spec.ts'
angular9以下版本可以使用命令ng test --main ./src/app/unit/test.spec.ts
或者使用fdescribe或fit,让程序只运行某个测试用例或测试用例集。
使用 ng test --help
可以查看其他相关命令参数。
配置
CLI 会生成 Jasmine 和 Karma 的配置文件。主要的配置文件包括karma.conf.js和test.ts。
karma.conf.js :文件是为了告知 Karma 需要启用哪些插件、加载哪些测试脚本、需要哪些测试浏览器环境、测试报告通知方式、日志等等。具体配置内容参见 karma.conf.js。https://karma-runner.github.io/5.0/config/configuration-file.html>
test.ts:angular.json 中指定的测试入口文件,其中初始化了测试环境以及指定所有测试文件。
测试文件的扩展名必须是 .spec.ts,这样工具才能识别出它是一个测试文件,也叫规约(spec)文件
运行命令
ng test --code-coverage
可启动代码覆盖率报告,或者angular.json 中配置为true,配置后每次直接运行ng test就会启动代码覆盖率报告"test": {
"options": {
"codeCoverage": true
}
}
Jasmine
Angular 单元测试是使用 Jasmine 框架来编写的。
基础知识
describe(string, function):是 Jasmine 的全局函数,可以理解为一个测试集(Test Suite),主要功能是用来划分单元测试的。describe 可以嵌套使用。
it(string, function):可以理解为测试用例。Specs 通过调用 it 的全局函数来定义。每个 Spec 包含一个或多个 expectations 期望值来测试需要测试代码。
Jasmine 中的每个 expectation 是一个断言,可以是 true 或者 false。当每个 Spec 中的所有 expectations 都是 true,则通过测试。有任何一个 expectation 是 false,则未通过测试。而方法的内容就是测试主体。
每个 Matchers 实现一个布尔值,在实际值和期望值之间比较。它负责通知 Jasmine,此 expectation 是真或者假。然后 Jasmine 会认为相应的 spec 是通过还是失败。所有的 expect 都可以使用 not 表示否定的断言。
JavaScript 的作用域的规则适用,所以在 describe 定义的变量对 Suite 中的任何 it 代码块都是可见的。
describe("The 'toBe' matcher compares with ===", function() {
it("and has a positive case ", function() {
expect(true).toBe(true);
});
it("and can have a negative case", function() {
expect(false).not.toBe(true);
});
});
Setup 和 Teardown
Setup 方法:
beforeAll:每个 suite(即 describe)中所有 spec(即 it)运行之前运行,整个suite里只运行一次
beforeEach:每个 spec(即 it)运行之前运行
Teardown 方法:
afterAll:每个 suite(即 describe)中所有 spec(即 it)运行之后运行
afterEach:每个 spec(即 it)运行之后运行
跳过或专注
在实际项目中,需要由于发布的版本需要选择测试用例包,xdescribe和xit能很方便的将不包含在版本中的测试用例排除在外。不过xdescribe和xit略有不同:
xdescribe:该 describe下的所有 it 将被忽略,jasmine 将直接忽略这些it,因此不会被运行
xit:运行到该 it 时,挂起它不执行
测试项目时,如果只需要运行某一个测试集可以使用 fdescribe 和 fit。
举例:组件测试
测试环境中创建一个组件,使用Angular TestBed进行测试。
TestBed 是 Angular 测试工具集提供的用于构建一个 @NgModule 测试环境。使用 TestBed.configureTestingModule() 来构建测试模块,它接受一个元数据对象,其中具有 @NgModule 中的绝大多数属性。
// 引入相关模块
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { RouterTestingModule } from '@angular/router/testing';
import { HttpClientTestingModule } from '@angular/common/http/testing';
import { BackupListComponent } from './backup-list.component';
import { DebugElement } from '@angular/core';
describe('HorizontalGridComponent test', () => {
let component: HorizontalGridComponent;
let fixture: ComponentFixture<HorizontalGridComponent>;
// 配置 TestBed 环境
beforeEach(async(() => {
TestBed.configureTestingModule({
imports: [
HttpClientTestingModule
],
declarations: [HorizontalGridComponent],
}).compileComponents();
}));
beforeEach(() => {
// 创建一个HorizontalGridComponent 的实例
fixture = TestBed.createComponent(HorizontalGridComponent);
// 使用 fixture.componentInstance 来访问组件实例
component = fixture.componentInstance;
// TestBed.createComponent 不能触发变更检测,使用 detectChanges() 触发检查。
fixture.detectChanges();
});
it('should create', () => {
expect(fixture).toBeDefined();
expect(component).toBeDefined();
});
it('should have <h3> with "Hello"', () => {
// const El: HTMLElement = fixture.nativeElement;
const De: DebugElement = fixture.debugElement;
const El: HTMLElement = De.nativeElement; // nativeElement相当于debugElement的一个属性
// js原生的querySelector api去获取h3标签
const p = El.querySelector('h3');
// 判断h3标签的内容
expect(p.textContent).toEqual('Hello');
});
it('should find the <h3> with fixture.debugElement.query(By.css)', () => {
const De: DebugElement = fixture.debugElement;
const El = De.query(By.css('h3')); // nativeElement相当于debugElement的一个属性
// js原生的querySelector api去获取h3标签
const p: HTMLElement = El.nativeElement;
// 判断h3标签的内容
expect(p.textContent).toEqual('Hello');
});
afterEach(() => {
TestBed.resetTestingModule();
});
});
配置 TestBed 环境,对于带有外部引用(样式、模板)的组件来说初始化时需要调用 compileComponents() 进行编译。由于 compileComponents 是异步的,所以要使用 async() 函数处理
置好 TestBed 之后,调用它的 createComponent() 方法,它会创建一个 HorizontalGridComponent 的实例,把相应的元素添加到测试运行器的 DOM 中,然后返回一个 ComponentFixture 对象。ComponentFixture 用来与所创建的组件及其 DOM 元素进行交互。
使用 fixture.componentInstance 来访问组件实例。
获取组件元素 nativeElement 和 DebugElement。 前者原生 DOM 元素,属性取决于运行环境,如果是浏览器,就提供浏览器的一些api,后者是由 Angular 进行包装可以安全的横跨其支持的所有平台运行并提供诸如 query 或者 triggerEventHandler 事件dom操作等方法。
使用 By 类支持跨平台应用。
运行完成后,控制台输出:
chrome浏览器输出:
- 点赞
- 收藏
- 关注作者
评论(0)