介绍
如果您的项目是使用Angular CLI创建的,那么一切都已准备就绪,您可以开始使用Jasmine作为测试框架和Karma作为测试运行程序编写测试。
Angular 还提供了诸如TestBed
和 之类的实用程序async
,使测试异步代码、组件、指令或服务更容易。
在本文中,您将了解如何使用 Jasmine 和 Karma 在 Angular 中编写和运行单元测试。
先决条件
要完成本教程,您需要:
- Node.js 安装在本地,您可以按照如何安装 Node.js 和创建本地开发环境来完成。
- 对设置 Angular 项目有一定的了解。
本教程已通过 Node v16.2.0、npm
v7.15.1 和@angular/core
v12.0.4 验证。
步骤 1 — 设置项目
您的测试文件通常放置在它们测试的文件旁边,但如果您愿意,它们也可以放在自己单独的目录中。
这些规范文件使用*.spec.ts
.
首先,使用@angular/cli
创建一个新项目:
- ng new angular-unit-test-example
然后,导航到新创建的项目目录:
- cd angular-unit-test-example
在 旁边app.component
,会有一个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 'angular-unit-test-example'`, () => {
const fixture = TestBed.createComponent(AppComponent);
const app = fixture.componentInstance;
expect(app.title).toEqual('angular-unit-test-example');
});
it('should render title', () => {
const fixture = TestBed.createComponent(AppComponent);
fixture.detectChanges();
const compiled = fixture.nativeElement;
expect(compiled.querySelector('.content span').textContent).toContain('angular-unit-test-example app is running!');
});
});
了解茉莉花
首先,了解 Jasmine 的一些重要事项:
describe
块定义了一个测试套件,每个it
块用于一个单独的测试。beforeEach
在每次测试之前运行并用于测试的setup
一部分。afterEach
在每次测试之后运行并用于测试的teardown
一部分。- 您也可以使用
beforeAll
andafterAll
,它们在所有测试之前或之后运行一次。 - 您在 Jasmine 中
expect
使用匹配器测试断言,如toBeDefined
,toBeTruthy
,toContain
,toEqual
,toThrow
,toBeNull
, … 例如:expect(myValue).toBeGreaterThan(3);
- 您可以使用以下方法进行否定断言
not
:expect(myValue).not.toBeGreaterThan(3);
- 您还可以定义自定义匹配器。
TestBed
是可用于特定于 Angular 的测试的主要实用程序。您将使用TestBed.configureTestingModule
在测试套件的beforeEach
块,并给它有类似值的一个对象作为一个普通NgModule
的declarations
,providers
和imports
。然后你可以链接一个调用来compileComponents
告诉 Angular 编译声明的组件。
您可以创建一个component fixture
与TestBed.createComponent
. 夹具可以访问 a debugElement
,这将使您可以访问组件夹具的内部结构。
更改检测不会自动完成,因此您将调用detectChanges
一个装置来告诉 Angular 运行更改检测。
将测试的回调函数或beforeEach
with的第一个参数包装起来,async
允许 Angular 执行异步编译并等待async
块内的内容准备好再继续。
了解测试
第一个测试被命名should create the app
,它用于expect
检查带有toBeTruthy()
.
第二个测试被命名should have as title 'angular-unit-test-example'
,它用于expect
检查app.title
值是否等于'angular-unit-test-example'
带有的字符串toEqual()
。
第三个测试被命名should render title
,它用于expect
检查'angular-unit-test-example app is running!'
带有toContain()
.
在您的终端中,运行以下命令:
- ng test
所有三个测试都将运行并显示测试结果:
Output3 specs, 0 failures, randomized with seed 84683
AppComponent
* should have as title 'angular-unit-test-example'
* should create the app
* should render title
目前所有三个测试都通过了。
第 2 步 – 构建示例组件
让我们创建一个递增或递减值的组件。
app.component.ts
在您的代码编辑器中打开并将以下代码行替换为increment
和decrement
逻辑:
import { Component } from '@angular/core';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
value = 0;
message!: string;
increment() {
if (this.value < 15) {
this.value += 1;
this.message = '';
} else {
this.message = 'Maximum reached!';
}
}
decrement() {
if (this.value > 0) {
this.value -= 1;
this.message = '';
} else {
this.message = 'Minimum reached!';
}
}
}
app.component.html
在您的代码编辑器中打开并将内容替换为以下代码:
<h1>{{ value }}</h1>
<hr>
<button (click)="increment()" class="increment">Increment</button>
<button (click)="decrement()" class="decrement">Decrement</button>
<p class="message">
{{ message }}
</p>
此时,您应该已经修改了app.component.ts
和 的版本app.component.html
。
第 3 步 – 构建测试套件
app.component.spec.ts
使用您的代码编辑器重新访问并将其替换为以下代码行:
import { TestBed, async, ComponentFixture } from '@angular/core/testing';
import { By } from '@angular/platform-browser';
import { DebugElement } from '@angular/core';
import { AppComponent } from './app.component';
describe('AppComponent', () => {
let fixture: ComponentFixture<AppComponent>;
let debugElement: DebugElement;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [
AppComponent
],
}).compileComponents();
fixture = TestBed.createComponent(AppComponent);
debugElement = fixture.debugElement;
}));
it('should increment and decrement value', () => {
fixture.componentInstance.increment();
expect(fixture.componentInstance.value).toEqual(1);
fixture.componentInstance.decrement();
expect(fixture.componentInstance.value).toEqual(0);
});
it('should increment value in template', () => {
debugElement
.query(By.css('button.increment'))
.triggerEventHandler('click', null);
fixture.detectChanges();
const value = debugElement.query(By.css('h1')).nativeElement.innerText;
expect(value).toEqual('1');
});
it('should stop at 0 and show minimum message', () => {
debugElement
.query(By.css('button.decrement'))
.triggerEventHandler('click', null);
fixture.detectChanges();
const message = debugElement.query(By.css('p.message')).nativeElement.innerText;
expect(fixture.componentInstance.value).toEqual(0);
expect(message).toContain('Minimum');
});
it('should stop at 15 and show maximum message', () => {
fixture.componentInstance.value = 15;
debugElement
.query(By.css('button.increment'))
.triggerEventHandler('click', null);
fixture.detectChanges();
const message = debugElement.query(By.css('p.message')).nativeElement.innerText;
expect(fixture.componentInstance.value).toEqual(15);
expect(message).toContain('Maximum');
});
});
我们直接在块中分配fixture
和debugElement
,beforeEach
因为我们所有的测试都需要这些。我们还通过导入ComponentFixture
from@angular/core/testing
和DebugElement
from 来对它们进行强类型化@angular/core
。
在我们的第一个测试中,我们调用组件实例本身的方法。
在剩下的测试中,我们使用我们的DebugElement
来触发按钮点击。注意DebugElement
有一个query
接受谓词的方法。在这里,我们使用该By
实用程序及其css
方法来查找模板中的特定元素。DebugElement
还有一个nativeElement
方法,用于直接访问DOM。
我们还在fixture.detectChanges
最后 3 个测试中使用来指示 Angular 在对 Jasmine 的expect
.
完成更改后,ng test
从终端运行命令:
- ng test
这将在监视模式下启动 Karma,因此每次文件更改时您的测试都会重新编译。
Output4 specs, 0 failures, randomized with seed 27239
AppComponent
* should increment value in template
* should increment and decrement value
* should stop at 0 and show minimum message
* should stop at 15 and show maximum message
所有四个测试都将通过。
结论
在本文中,您将了解如何使用 Jasmine 和 Karma 在 Angular 中编写和运行单元测试。现在您已经了解了主要的 Angular 测试实用程序,并且可以开始为简单的组件编写测试了。
继续学习测试具有依赖项的组件、测试服务以及使用模拟、存根和间谍。
您还可以参考官方文档以获取深入的 Angular 测试指南。