简介
如果您的项目是使用Angular CLI,]创建的,那么您就可以开始使用Jasmine作为测试框架和Karma作为测试运行者)编写测试了。
ANGLE还提供了TestBed
和async
等实用工具,以简化对异步代码、组件、指令或服务的测试。
在本文中,您将了解如何使用Jasmine和Karma编写和运行单元测试。
前提条件
要完成本教程,您需要:
- 本地安装node.js,可按照如何安装node.js并创建本地开发Environment.
- 对设置角度project.》有所了解
本教程已经在Node v16.2.0、npm
v7.15.1和@angular/core
v12.0.4上进行了验证。
第一步-设置项目
您的测试文件通常放在它们测试的文件旁边,但是如果您愿意的话,它们也可以放在它们自己的单独目录中。
这些规范文件使用* .spec.ts
命名约定。
首先,使用@angular/cli
创建一个新项目:
1ng new angular-unit-test-example
然后,导航到新创建的项目目录:
1cd angular-unit-test-example
在app.Component
旁边会有一个app.Component.spec.ts
文件。打开此文件并检查其内容:
1[label src/app/app.component.spec.ts]
2import { TestBed } from '@angular/core/testing';
3import { AppComponent } from './app.component';
4
5describe('AppComponent', () => {
6 beforeEach(async () => {
7 await TestBed.configureTestingModule({
8 declarations: [
9 AppComponent
10 ],
11 }).compileComponents();
12 });
13
14 it('should create the app', () => {
15 const fixture = TestBed.createComponent(AppComponent);
16 const app = fixture.componentInstance;
17 expect(app).toBeTruthy();
18 });
19
20 it(`should have as title 'angular-unit-test-example'`, () => {
21 const fixture = TestBed.createComponent(AppComponent);
22 const app = fixture.componentInstance;
23 expect(app.title).toEqual('angular-unit-test-example');
24 });
25
26 it('should render title', () => {
27 const fixture = TestBed.createComponent(AppComponent);
28 fixture.detectChanges();
29 const compiled = fixture.nativeElement;
30 expect(compiled.querySelector('.content span').textContent).toContain('angular-unit-test-example app is running!');
31 });
32});
了解茉莉花
首先,关于茉莉,有几件事是必须知道的:
Describe
块定义一个测试套件,每个it
块用于单独的测试。beForeEach
在每次测试之前运行,用于测试的setup
部分。After Each
在每次测试后运行,用于测试的`teardown‘部分。- 您也可以使用
bepreAll
和After All
,它们在所有测试之前或之后运行一次。 - 您可以在Jasmine中使用
expect
测试断言,并使用toBeDefined
、toBeTruthy
、toContain
、toEqual
、toThrow
、toBeNull
、...例如:Expect(MyValue).toBeGreaterThan(3);
- 可以用
not
进行否定断言:expect(MyValue).not.toBeGreaterThan(3);
- 您也可以定义自定义匹配器。
TestBed
是用于特定角度测试的主要工具。您将在测试套件的beforEach
块中使用TestBed.figureTestingModule
,并为其提供一个对象,该对象的值与常规声明
、提供者
和导入
的NgModule
的值相似。然后,您可以链接一个对complementeComponents
的调用,以告诉ANGLE编译声明的组件。
您可以使用TestBed.createComponent
创建一个组件装置
。灯具可以访问debugElement
,这将使您能够访问组件灯具的内部。
变化检测不是自动完成的,所以您将在一个装置上调用DetectChanges
来告诉ANGLE运行变化检测。
使用async
包装测试的回调函数或bepreEach
的第一个参数,可以让ANGLE执行异步编译,并等待async
块内部的内容准备就绪后再继续。
理解测试
第一个测试名为应该创建App
,它使用expect
通过toBeTruthy()
检查组件是否存在。
第二个测试被命名为应当有作为标题的角度-单元-测试-示例‘
,它使用expect
来检查app.tile
值是否等于带有toEqual()
的字符串`’角度-单元-测试-示例‘’。
第三个测试名为应当呈现标题
,它使用expect
通过toContain()
检查编译后的代码中是否有文本‘角度-单元-测试-示例应用程序正在运行!’
。
在您的终端中,运行以下命令:
1ng test
将运行所有三个测试,并显示测试结果:
1[secondary_label Output]
23 specs, 0 failures, randomized with seed 84683
3AppComponent
4* should have as title 'angular-unit-test-example'
5* should create the app
6* should render title
这三项测试目前都在通过。
第二步-构建示例组件
让我们创建一个递增或递减某个值的组件。
在您的代码编辑器中打开app.Component.ts
,并将以下代码行替换为increment
和ducment
逻辑:
1[label src/app/app.component.ts]
2import { Component } from '@angular/core';
3
4@Component({
5 selector: 'app-root',
6 templateUrl: './app.component.html',
7 styleUrls: ['./app.component.css']
8})
9export class AppComponent {
10 value = 0;
11 message!: string;
12
13 increment() {
14 if (this.value < 15) {
15 this.value += 1;
16 this.message = '';
17 } else {
18 this.message = 'Maximum reached!';
19 }
20 }
21
22 decrement() {
23 if (this.value > 0) {
24 this.value -= 1;
25 this.message = '';
26 } else {
27 this.message = 'Minimum reached!';
28 }
29 }
30}
在代码编辑器中打开app.Component.html
,并将内容替换为以下代码:
1[label src/app/app.component.html]
2<h1>{{ value }}</h1>
3
4<hr>
5
6<button (click)="increment()" class="increment">Increment</button>
7
8<button (click)="decrement()" class="decrement">Decrement</button>
9
10<p class="message">
11 {{ message }}
12</p>
至此,您应该已经有了app.Component.ts
和app.Component.html
的修订版本。
Step 3 -构建测试套件
使用您的代码编辑器重新访问app.Component.spec.ts
,并将其替换为以下代码行:
1[label src/app/app.component.spec.ts]
2import { TestBed, async, ComponentFixture } from '@angular/core/testing';
3import { By } from '@angular/platform-browser';
4import { DebugElement } from '@angular/core';
5
6import { AppComponent } from './app.component';
7
8describe('AppComponent', () => {
9 let fixture: ComponentFixture<AppComponent>;
10 let debugElement: DebugElement;
11
12 beforeEach(async(() => {
13 TestBed.configureTestingModule({
14 declarations: [
15 AppComponent
16 ],
17 }).compileComponents();
18
19 fixture = TestBed.createComponent(AppComponent);
20 debugElement = fixture.debugElement;
21 }));
22
23 it('should increment and decrement value', () => {
24 fixture.componentInstance.increment();
25 expect(fixture.componentInstance.value).toEqual(1);
26
27 fixture.componentInstance.decrement();
28 expect(fixture.componentInstance.value).toEqual(0);
29 });
30
31 it('should increment value in template', () => {
32 debugElement
33 .query(By.css('button.increment'))
34 .triggerEventHandler('click', null);
35
36 fixture.detectChanges();
37
38 const value = debugElement.query(By.css('h1')).nativeElement.innerText;
39
40 expect(value).toEqual('1');
41 });
42
43 it('should stop at 0 and show minimum message', () => {
44 debugElement
45 .query(By.css('button.decrement'))
46 .triggerEventHandler('click', null);
47
48 fixture.detectChanges();
49
50 const message = debugElement.query(By.css('p.message')).nativeElement.innerText;
51
52 expect(fixture.componentInstance.value).toEqual(0);
53 expect(message).toContain('Minimum');
54 });
55
56 it('should stop at 15 and show maximum message', () => {
57 fixture.componentInstance.value = 15;
58 debugElement
59 .query(By.css('button.increment'))
60 .triggerEventHandler('click', null);
61
62 fixture.detectChanges();
63
64 const message = debugElement.query(By.css('p.message')).nativeElement.innerText;
65
66 expect(fixture.componentInstance.value).toEqual(15);
67 expect(message).toContain('Maximum');
68 });
69});
我们在bepreEach
块中直接赋值fix ture
和debugElement
,因为我们的所有测试都需要它们。我们也会通过从@Angel/core/Testing
导入ComponentFixture
和从@Angel/core
导入DebugElement
来强类型它们。
在我们的第一个测试中,我们调用组件实例本身的方法。
在剩下的测试中,我们使用DebugElement
触发按钮点击。注意DebugElement
是如何有一个带有谓词的query
方法的。这里我们使用By
实用工具及其css
方法来查找模板中的特定元素。DebugElement
还有一个nativeElement
方法,用于直接访问DOM。
在对Jasmine的expect
进行断言之前,我们还在最后3个测试中使用了Fixture.DetectChanges
来指示角度运行变化检测。
完成更改后,从终端运行ng test
命令:
1ng test
这将在监视模式下启动Karma,因此您的测试将在每次文件更改时重新编译。
1[secondary_label Output]
24 specs, 0 failures, randomized with seed 27239
3AppComponent
4* should increment value in template
5* should increment and decrement value
6* should stop at 0 and show minimum message
7* should stop at 15 and show maximum message
所有四项测试都将通过。
结论
在本文中,您将了解如何使用Jasmine和Karma编写和运行单元测试。现在您已经了解了主要的角度测试实用程序,可以开始编写简单组件的测试了。
通过测试依赖组件、测试服务以及使用mocks,stubs和spies继续学习。
您也可以参考官方documentation]获取深入的角度测试指南。