Angular单元测试:Karma和Jasmine
Angular单元测试检查Angular应用程序中的隔离代码片段。它允许用户在不中断应用程序的任何其他部分的情况下添加新功能。Jasmine是一个Javascript测试框架,Karma是一个基于Node的JavaScript代码的测试工具,可跨多个真实浏览器进行测试 。本博客将帮助您开始使用Karma和Jasmine进行Angular单元测试。
Angular单元测试简介
首先,您必须在您的计算机上安装Angular。这是您需要开始安装Angular的地方。如果您已经安装了Angular,请随意跳过下一步。
创建和管理Angular项目非常容易。有各种竞争库、框架和工具可以解决这些问题。Angular团队创建了Angular CLI,这是一个用于简化Angular项目的命令行工具。Angular CLI通过npm安装,因此您需要在您的计算机上安装Node。
安装Node后,您可以在终端中运行以下命令。
安装完成所需的时间可能会有所不同。完成后,您可以在终端中输入以下命令来查看Angular CLI的版本。
现在您已经安装了Angular CLI,可以准备创建一个Angular示例应用程序。在您的终端中运行以下命令。
ng new angular-unit-test-application
执行该命令后,您将被询问是否要添加Angular路由。键入Y并按ENTER。然后,您将被要求在应用程序的样式表格式之间进行选择。这将需要几分钟时间,一旦完成,您将转到您的测试应用程序。
单元测试测试了代码的隔离单元。单元测试旨在回答诸如:
- 排序函数是否按正确的顺序对列表进行了排序?
- 我是否能正确地思考逻辑?
为了回答这些问题,关键是要隔离正在测试的代码单元。这是因为当您测试排序函数时,您不希望被迫创建相关的部分,比如进行任何API调用以获取实际数据库数据进行排序。
您已经知道单元测试测试软件或应用程序的各个组件。这样做的主要动机是检查所有单独的部分是否按预期工作。单元是可以测试的软件的最小可能组件。通常,它有几个输入和一个输出。
让我们进入Angular Web应用程序测试部分。
在您的终端中运行以下命令。
等待几秒钟后,您将看到一个新的浏览器窗口打开,显示如下所示的页面。
解析Karma和Jasmine在Angular单元测试中的作用
什么是Karma测试运行器?
Karma是由Angular JS团队开发的测试自动化工具,因为使用当前工具测试他们自己的框架特性变得困难。因此,他们开发了Karma,并将其转换为Angular开发的应用程序的默认测试运行器。除了与Angular兼容外,它还提供了灵活性,可以根据您的工作流程定制Karma。它可以选择在不同的浏览器和设备(如平板电脑、手机等)上测试您的代码。Karma为您提供了将Jasmine替换为其他测试框架(如Mocha和QUnit)的选项。
以下是示例项目中karma.conf.js文件的内容。
什么是Jasmine? Jasmine是一个免费的开源行为驱动开发(BDD)框架,用于测试JavaScript代码,并且与Karma兼容。与Karma一样,它也是Angular文档中建议的测试框架。
测试运行的流程如下,
测试组件 add-organization.component.ts
// 代码块内容不需要翻译,原文输出
add-organization.component.spec.ts
// 代码块内容不需要翻译,原文输出
在这个组件中,你可以看到下面列出的一些测试事项:
- Angular响应式表单验证
- 条件变量和路由调用
- 多种情况覆盖分支和语句
- 弹出模态框,包括确认和取消
- 提交表单数据并调用post API,同时也会涉及错误处理部分
- 使用API调用获取组织详情
所有这些事项都将在我们的规范文件中进行测试。你可以在上面的图像中看到,它将涵盖所有的语句、函数、分支等。
从上面的代码片段中,你会注意到多个事项。下面是每个事项的解释:
- 我们使用
describe
来开始我们的测试,并在其中给出了我们要测试的组件的名称。 - 我们可以在每个规范执行之前执行一些代码片段。这个功能对于在应用程序中运行通用代码非常有用。
- 在
beforeEach
中,我们有TestBed.ConfigureTestingModule
。TestBed
设置了适合我们测试的配置并初始化了环境。ConfigureTestingModule
设置了允许我们测试组件的模块。你可以说它为我们的测试环境创建了一个模块,并在其中声明了导入和提供者。
测试服务
1. Organization.service.ts
import { HttpClient } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { HttpBaseService } from '../shared/services/httpbase/httpbase.service';
import { LanguageService } from '../shared/services/language/language.service';
@Injectable({
providedIn: 'root'
})
export class OrganizationService extends HttpBaseService {
constructor(httpClient: HttpClient, languageService: LanguageService) {
super(httpClient, languageService);
}
prepareOrganizationListResponse(resList: any[]) {
let organizationList: any = [];
let organization: any = {};
resList.forEach(list => {
organization.lastName = list.lastName,
organization.firstName = list.firstName,
organization.email = list.email,
organization.isActive = list.isActive
organizationList.push(organization);
});
return organizationList;
}
prepareOrganizationDetailsResponse(res: any) {
return {
lastName: res.lastName,
firstName: res.firstName,
email: res.email,
isActive: res.isActive
};
}
}
2. Organization.service.spec.ts
import { SharedModule } from 'src/app/shared/modules/shared.module';
import { HttpClientModule } from '@angular/common/http';
import { TestBed } from '@angular/core/testing';
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
import { TranslateModule, TranslateLoader, TranslateFakeLoader, TranslateService } from '@ngx-translate/core';
import { HttpBaseService } from '../shared/services/httpbase/httpbase.service';
import { SharedService } from '../shared/services/shared.service';
import { OrganizationService } from './organization.service';
import { OrganizationConfigurationApi, OrganizationListItemUI } from './organization.model';
describe('OrganizationService', () => {
let service: OrganizationService;
beforeEach(() => {
TestBed.configureTestingModule({
imports: [
HttpClientModule,
SharedModule,
TranslateModule.forRoot({
loader: {
provide: TranslateLoader,
useClass: TranslateFakeLoader
}
}),
],
providers: [
TranslateService,
HttpBaseService,
SharedService,
{ provide: MAT_DIALOG_DATA, useValue: {} },
{ provide: MatDialogRef, useValue: {} }
]
}).compileComponents();
service = TestBed.inject(OrganizationService);
});
it('should be created', () => {
expect(service).toBeTruthy();
});
it('should be return properly formatted organization list response', () => {
let organization: any = {};
organization.lastName = 'lastName',
organization.firstName = 'firstName',
organization.email = 'test@gmail.com',
organization.isActive = true,
expect(service.prepareOrganizationListResponse(
[
{
lastName: 'lastName',
firstName: 'firstName',
email: 'test@gmail.com',
isActive: true,
}
]
)).toEqual([organization]);
});
it('should be return organization details response', () => {
expect(service.prepareOrganizationDetailsResponse({
lastName: 'lastName',
还没有评论,来说两句吧...