x:12 y:9,求角度
在本指南中,我们将研究如何在Angular 5项目中编写自动化测试。 Angular Testing是每个使用Angular CLI或Angular快速启动项目设置的项目中可用的核心功能。
Angular测试的主题非常广泛,因为它是一个复杂且非常复杂的主题。 要完全覆盖它,将需要几章或一门全长课程。 因此,在本指南中,我将向您展示入门的基础知识。
先决条件
在撰写本文时,Angular 5.2是当前的稳定版本-这就是我们将在此处使用的版本。 本指南假定您至少对Angular 4+基础有扎实的了解。 还假定您至少了解概念或具有一些编写自动化测试的技能。
我们将基于Angular的官方初学者教程建立测试示例,以演示如何编写组件和服务的测试。 您可以在我们的GitHub存储库上找到带有测试的完整代码。 在本指南的最后,您应该具备在Angular 5中实施多个通过测试的技能。
角度测试技术
如您所知,一个Angular项目由模板,组件,服务和模块组成。 它们都在称为Angular的环境中运行。 尽管可以编写隔离的测试,但您实际上并不知道您的代码将如何与Angular环境中的其他元素进行交互。
幸运的是,我们有几种技术可以帮助我们以最少的精力编写此类单元测试。
1.角度测试实用程序
这是为Angular代码构建测试环境所需的一组类和函数。 您可以在Angular的api文档中找到它们。 最重要的是TestBed 。 它用于配置Angular模块的方式与@NgModule
相同,只是它准备了要测试的模块。 它具有configureTestingModule
函数,您可以在其中提供所有必需的依赖关系,以使组件在测试环境中起作用。 这是准备在测试环境中运行的dashboard component
的示例。 该组件需要几个依赖项才能运行测试:
TestBed.configureTestingModule({
imports: [ RouterTestingModule ],
declarations: [ DashboardComponent ],
schemas: [ NO_ERRORS_SCHEMA ],
providers: [
{
provide: HeroService,
useClass: MockHeroService
}
],
})
.compileComponents();
我们将在下面更进一步地仔细研究这里发生的事情。
2.茉莉花
Jasmine是编写Angular测试的事实框架。 基本上,这是一个使用行为驱动的表示法的测试框架。 用Jasmine编写测试非常简单:
describe('createCustomer' () => {
it('should create new customer',(customer) => {
...
expect(response).toEqual(newCustomer)
});
it('should not create customer with missing fields', () => {
...
expect(response.error.message).toEqual('missing parameters')
});
it('should not create customer with existing record', () => {
...
expect(response.error.message).toEqual('record already exists')
});
});
茉莉花测试的解剖结构至少由两个元素组成:一个describe
函数(它是一组测试)和一个it
函数(它是测试本身)。 通常,我们使用describe
来指示我们关注的功能,例如createCustomer()
。 然后,在套件中,我们创建多个it
测试。 每个测试都将目标函数置于不同的条件下,以确保其行为符合预期。 您可以参考Jasmine文档以获得更多信息。
3.因果报应
Karma是用于在浏览器环境中针对测试代码执行源代码的工具。 它支持在为其配置的每个浏览器中运行测试。 结果显示在命令行和浏览器上,供开发人员检查哪些测试通过或失败。 业力还监视文件,并且只要文件发生更改,就可以触发测试重新运行。 在Angular项目的根目录下,我们具有用于配置Karma的文件karma.conf
。 内容应如下所示:
module.exports = function (config) {
config.set({
basePath: '',
frameworks: ['jasmine', '@angular/cli'],
plugins: [
require('karma-jasmine'),
require('karma-chrome-launcher'),
require('karma-jasmine-html-reporter'),
require('karma-coverage-istanbul-reporter'),
require('@angular/cli/plugins/karma')
],
client:{
clearContext: false // leave Jasmine Spec Runner output visible in browser
},
coverageIstanbulReporter: {
reports: [ 'html', 'lcovonly' ],
fixWebpackSourcePaths: true
},
angularCli: {
environment: 'dev'
},
reporters: ['progress', 'kjhtml'],
port: 9876,
colors: true,
logLevel: config.LOG_INFO,
autoWatch: true,
browsers: ['Chrome'],
singleRun: false
});
};
请查看Karma的配置文档以了解如何对其进行自定义。 如您所见,Chrome被列为用于运行测试的浏览器。 您需要定义一个名为CHROME_BIN
的环境变量,该变量指向您的Chrome浏览器可执行文件的位置。 如果您使用的是Linux,只需将此行添加到.bashrc
文件中:
export CHROME_BIN="/usr/bin/chromium-browser"
为了让Karma运行测试,您必须确保测试文件以.spec.ts
。 您应该注意,Karma设计为主要运行单元测试。 要运行端到端测试,我们需要另一个工具Protractor,接下来我们将对其进行研究。
4.量角器
量角器是Angular的端到端测试框架。 它在真实的浏览器中运行测试,并像真实的人一样与之交互。 与单元测试不同,在单元测试中我们测试各个功能,而在这里我们测试整个逻辑。 量角器能够填写表格,单击按钮,并确认预期的数据和样式显示在HTML文档中。 就像噶,量角器有你的角项目的根,自己的配置文件protractor.conf
:
const { SpecReporter } = require('jasmine-spec-reporter');
exports.config = {
allScriptsTimeout: 11000,
specs: [
'./e2e/**/*.e2e-spec.ts'
],
capabilities: {
'browserName': 'chrome'
},
directConnect: true,
baseUrl: 'http://localhost:4200/',
framework: 'jasmine',
jasmineNodeOpts: {
showColors: true,
defaultTimeoutInterval: 30000,
print: function() {}
},
onPrepare() {
require('ts-node').register({
project: 'e2e/tsconfig.e2e.json'
});
jasmine.getEnv().addReporter(new SpecReporter({ spec: { displayStacktrace: true } }));
}
};
您可以在此处找到有关其配置的文档。 与Jasmine / Karma测试不同,量角器测试位于src
文件夹之外的e2e
文件夹中。 我们稍后将研究编写端到端测试。 现在,让我们开始编写单元测试。
写作单元测试
如前所述,Angular附带了为项目编写自动化测试所需的一切。 要开始测试,只需运行以下命令:
ng test
业力将加速运行所有可用的测试。 假设您刚刚完成了“英雄之旅”教程,则应该有类似的报告,如下所示:
免费学习PHP!
全面介绍PHP和MySQL,从而实现服务器端编程的飞跃。
原价$ 11.95 您的完全免费
这些测试是在使用Angular CLI
工具生成组件,服务和类时创建的。 在创建时,这些测试中的代码是正确的。 但是,当您向组件和服务中添加代码时,测试就失败了。 在下一节中,我们将看到如何解决损坏的测试。
测试组件
对组件进行单元测试可以通过两种方式进行。 您可以单独对其进行测试,也可以在Angular环境中对其进行测试,以查看其如何与其模板和依赖项进行交互。 后者听起来很难实现,但是使用Angular Testing Utilities使创建测试更加容易。 这是使用Angular CLI
工具创建组件时为您生成的测试代码的示例:
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { HeroesComponent } from './heroes.component';
describe('HeroesComponent', () => {
let component: HeroesComponent;
let fixture: ComponentFixture<HeroesComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ HeroesComponent ]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(HeroesComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should be created', () => {
expect(component).toBeTruthy();
});
});
在第一个beforeEach()
函数中,我们使用TestBed.configureTestingModule
函数创建用于测试组件的模块环境。 它类似于NgModules ,除了在这种情况下,我们正在创建一个用于测试的模块。
在第二个beforeEach()
函数中,我们创建了component-under-test
的实例。 完成此操作后,我们将无法再次配置TestBed
,因为将引发错误。
最后,我们有了should be created
的规范,我们should be created
其中确认component
已初始化。 如果此测试通过,则表示组件应在Angular环境中正常运行。 但是,如果失败,则可能是组件具有一定的依赖关系,而我们并未将其包含在测试配置中。 让我们看看如何处理不同的问题。
测试使用另一个组件的组件
在Angular中构建用户界面时,我们经常通过选择器引用模板文件中的其他组件。 看一下以下示例dashboard.component.html
:
<h3>Top Heroes</h3>
...
</div>
<app-hero-search></app-hero-search>
在此示例中,我们引用具有选择器app-hero-search
另一个组件。 如果尝试按原样运行初始测试,它将失败。 这是因为我们尚未在测试环境中声明引用的组件。 在单元测试中,我们将所有精力都放在要测试的组件上。 在单元测试中,其他组件对我们而言并不重要。 我们必须假设它们正在按预期工作。 在我们的测试中包括引用的组件可能会污染结果。 要解决此问题,我们可以模拟引用的组件,也可以使用NO_ERRORS_SCHEMA
指令将其忽略。 这是一个例子:
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { NO_ERRORS_SCHEMA } from '@angular/core';
import { DashboardComponent } from './dashboard.component';
describe('DashboardComponent', () => {
let component: DashboardComponent;
let fixture: ComponentFixture<DashboardComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ DashboardComponent ],
schemas: [ NO_ERRORS_SCHEMA
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(DashboardComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should be created', () => {
expect(component).toBeTruthy();
});
});
现在,此测试应该不会出现组件依赖性问题。 但是,此测试尚未通过,因为还有另一种情况我们必须处理……
测试使用模块的组件
这次让我们检查一下hero-detail.component.html
:
<div *ngIf="hero">
<h2>{{ hero.name | uppercase }} Details</h2>
<div><span>id: </span>{{hero.id}}</div>
<div>
<label>name:
<input [(ngModel)]="hero.name" placeholder="name"/>
</label>
</div>
<button (click)="goBack()">go back</button>
<button (click)="save()">save</button>
</div>
在这里,我们使用的是ngModel
指令,该指令来自FormsModule
库。 为了编写支持该模块的测试,我们只需要导入FormsModule
并将其包含在TestBed
配置中:
import { FormsModule } from '@angular/forms';
...
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ HeroDetailComponent ],
imports: [ FormsModule],
})
.compileComponents();
}));
...
那应该可以解决FormsModule
的问题。 但是,我们需要在测试环境中指定更多的依赖项。
测试使用路由模块的组件
让我们研究一下hero-detail.component.ts
构造函数:
constructor(
private route: ActivatedRoute,
private location: Location,
private heroService: HeroService
) {}
该组件具有处理路由的ActivatedRoute
和Location
依赖性。 在我们的测试代码hero-detail.component.spec.ts
,我们可以实现类的模拟版本。 但是,我发现最好的解决方案是这样导入RouterTestingModule
:
import { RouterTestingModule } from ’@angular/router/testing’;
...
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ HeroDetailComponent ],
imports: [ FormsModule, RouterTestingModule ],
})
.compileComponents();
}));
RoutingTestingModule
可以轻松解决我们测试代码中的ActivateRoute
和Location
依赖关系。 RoutingTestingModule
还可以处理涉及路由的其他情况。 在dashboard.component.html
查看以下代码:
<h3>Top Heroes</h3>
<div class="grid grid-pad">
<a *ngFor="let hero of heroes" class="col-1-4" routerLink="/detail/{{hero.id}}">
<div class="module hero">
<h4>{{hero.name}}</h4>
</div>
</a>
</div>
注意,我们有一个名为routerLink
的指令。 这是AppRoutingModule
库提供的指令。 如果运行仪表板测试,则由于该依赖性而将失败。 要解决此问题,只需在dashboard.component.spec.ts
实现RoutingTestingModule
,就像我们对hero-detail.component.spec.ts
所做hero-detail.component.spec.ts
。
现在让我们看一下如何测试依赖于服务的组件。
测试使用服务的组件
每个组件至少需要一个服务来处理逻辑。 有两种测试使用服务的组件的方法。 让我们看一下message.service.ts
,它正在由message.component.ts
:
import { Injectable } from ’@angular/core’;
@Injectable()
export class MessageService {
messages: string[] = [];
add(message: string) {
this.messages.push(message);
}
clear() {
this.messages = [];
}
}
MessageService
具有非常简单的实现。 它不使用任何外部依赖项。 虽然建议从单元测试中排除外部逻辑,但是我们将在这里做一个例外。 我认为不需要使测试复杂化。 因此,我认为最好在测试中包含该服务。 这是message.component.spec.ts
的测试代码:
import { MessageService } from '@services/message.service';
...
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ MessagesComponent ],
providers: [ MessageService ]
})
.compileComponents();
}))
现在让我们看看另一个服务hero-service.ts
:
import { Injectable } from '@angular/core';
import { Observable } from 'rxjs/Observable';
import { of } from 'rxjs/observable/of';
import { HttpClient, HttpHeaders } from '@angular/common/http';
import { catchError, map, tap } from 'rxjs/operators';
...
@Injectable()
export class HeroService {
private heroesUrl = 'api/heroes';
constructor(
private http: HttpClient,
private messageService: MessageService) { }
/** GET heroes from the server */
getHeroes (): Observable<Hero[]> {
return this.http.get<Hero[]>(this.heroesUrl)
.pipe(
tap(heroes => this.log(`fetched ${heroes.length} heroes`)),
catchError(this.handleError('getHeroes', []))
);
}
getHero(id: number): Observable<Hero> {
const url = `${this.heroesUrl}/${id}`;
return this.http.get<Hero>(url).pipe(
tap(_ => this.log(`fetched hero id=${id}`)),
catchError(this.handleError<Hero>(`getHero id=${id}`))
);
}
...
}
HeroService
类包含很多逻辑-总共约104行。 它具有多个依赖关系,包括一个到另一个服务。 而且,其所有功能都是异步的。 这种复杂的代码很可能会污染我们的单元测试。 因此,我们应排除其逻辑。 我们通过创建模拟版本的hero.service.ts
做到这hero.service.ts
。 只需创建一个新文件,并将其hero.service.mock.ts
。 模拟其功能,以剥离其核心逻辑:
import { Observable } from 'rxjs/Observable';
import { of } from 'rxjs/observable/of';
import { Hero } from '@models/hero.model';
export class MockHeroService {
getHeroes(): Observable<Hero[]> {
return of([]);
}
getHero() {
return of({});
}
}
您可以看到模拟版本更简单。 现在,它污染我们的单元测试的可能性为零。 要将其包含在我们的组件规格文件中,我们可以这样实现:
import { HeroService } from '@services/hero.service';
import { MockHeroService } from '@services/hero.service.mock';
...
TestBed.configureTestingModule({
declarations: [ HeroDetailComponent ],
imports: [ FormsModule, RouterTestingModule ],
providers: [
{
provide: HeroService,
useClass: MockHeroService
},
],
})
.compileComponents();
}));
...
我们使用providers
选项将MockHeroService
注入我们的服务。 使用该服务为所有组件的测试代码实现此功能。
测试服务
现在,我们已经处理了测试组件时发生的一些常见情况,下面让我们看一下如何测试服务。 服务执行应用程序的核心逻辑,因此,全面测试其功能非常重要。 如前所述,Angular测试是一个很深的主题,因此我们只是在这里进行介绍。
打开hero.service.ts
并检查功能。 让我突出几个:
...
/** GET heroes from the server */
getHeroes (): Observable<Hero[]> {
return this.http.get<Hero[]>(this.heroesUrl)
.pipe(
tap(heroes => this.log(`fetched ${heroes.length} heroes`)),
catchError(this.handleError('getHeroes', []))
);
}
/** UPDATE: update selected hero on the server */
updateHero (hero: Hero): Observable<any> {
return this.http.put(this.heroesUrl, hero, httpOptions).pipe(
tap(_ => this.log(`updated hero id=${hero.id}`)),
catchError(this.handleError<any>('updateHero'))
);
}
...
每个函数由几行代码组成,但仍在继续。 为了全面测试每种情况,我们需要考虑多种情况。 当我们执行getHeroes()
,服务器可能
- 发回英雄名单
- 发回一个空清单
- 抛出错误
- 无法回应。
您也许可以考虑将更多可能的方案添加到列表中。 现在我们已经考虑了可能的场景,是时候编写测试了。 这是一个如何为HeroService
编写spec
的HeroService
:
import { TestBed, inject } from '@angular/core/testing';
import { HttpClientModule, HttpClient, HttpResponse } from '@angular/common/http';
import { HttpClientTestingModule, HttpTestingController } from '@angular/common/http/testing';
import { HeroService } from './hero.service';
import { MessageService } from './message.service';
import { Hero } from '@models/hero.model';
const mockData = [
{ id: 1, name: 'Hulk' },
{ id: 2, name: 'Thor'},
{ id: 3, name: 'Iron Man'}
] as Hero[];
describe('HeroService', () => {
let service;
let httpTestingController: HttpTestingController;
beforeEach(() => {
TestBed.configureTestingModule({
imports: [
HttpClientTestingModule
],
providers: [HeroService, MessageService]
});
httpTestingController = TestBed.get(HttpTestingController);
});
beforeEach(inject([HeroService], s => {
service = s;
}));
beforeEach(() => {
this.mockHeroes = [...mockData];
this.mockHero = this.mockHeroes[0];
this.mockId = this.mockHero.id;
});
const apiUrl = (id: number) => {
return `${service.heroesUrl}/${this.mockId}`;
};
afterEach(() => {
// After every test, assert that there are no more pending requests.
httpTestingController.verify();
});
it('should be created', () => {
expect(service).toBeTruthy();
});
describe('getHeroes', () => {
it('should return mock heroes', () => {
service.getHeroes().subscribe(
heroes => expect(heroes.length).toEqual(this.mockHeroes.length),
fail
);
// Receive GET request
const req = httpTestingController.expectOne(service.heroesUrl);
expect(req.request.method).toEqual('GET');
// Respond with the mock heroes
req.flush(this.mockHeroes);
});
});
describe('updateHero', () => {
it('should update hero', () => {
service.updateHero(this.mockHero).subscribe(
response => expect(response).toEqual(this.mockHero),
fail
);
// Receive PUT request
const req = httpTestingController.expectOne(service.heroesUrl);
expect(req.request.method).toEqual('PUT');
// Respond with the updated hero
req.flush(this.mockHero);
});
});
describe('deleteHero', () => {
it('should delete hero using id', () => {
const mockUrl = apiUrl(this.mockId);
service.deleteHero(this.mockId).subscribe(
response => expect(response).toEqual(this.mockId),
fail
);
// Receive DELETE request
const req = httpTestingController.expectOne(mockUrl);
expect(req.request.method).toEqual('DELETE');
// Respond with the updated hero
req.flush(this.mockId);
});
it('should delete hero using hero object', () => {
const mockUrl = apiUrl(this.mockHero.id);
service.deleteHero(this.mockHero).subscribe(
response => expect(response).toEqual(this.mockHero.id),
fail
);
// Receive DELETE request
const req = httpTestingController.expectOne(mockUrl);
expect(req.request.method).toEqual('DELETE');
// Respond with the updated hero
req.flush(this.mockHero.id);
});
});
});
这只是我们应该如何为与HttpClientModule
交互的服务编写测试的示例。 检查每个测试,并注意我们正在使用HttpTestingController
类来拦截请求。 在此测试中,我们将控制输入和输出以创建不同的场景。 这些测试的主要目的是确保我们的服务方法能够优雅地处理每种情况。 请注意,我们尚未完全实现hero.service.spec.ts
所需的所有测试,因为这超出了本指南的范围。
在本指南结束之前,我们仍然需要查看更多主题。
端到端角度测试
单元测试可确保组件和服务在受控的测试环境中正确运行。 但是,不能保证组件和服务将在Angular环境中相互交互。 这就是为什么我们需要执行端到端测试。 端到端测试是一种模拟人工测试的测试。 换句话说,这些测试旨在通过浏览器界面以与我们相同的方式与我们的应用程序进行交互。
在我们的英雄之旅应用程序中,我们可以测试一些用例,例如确保-
- 仪表盘组件上显示五个英雄
- 所有英雄均显示在英雄组件上
- 导航链接没有损坏
- 可以创建一个新英雄
- 英雄可以更新
- 英雄可以删除。
随着更多功能的实现,您可以继续添加到此列表中。 理想的端到端测试包含两个部分。
第一部分是一个帮助程序文件,提供了特定于组件的帮助程序功能。 这是app.po.ts
的示例:
import { browser, by, element } from 'protractor';
export class AppPage {
navigateTo() {
return browser.get('/');
}
getParagraphText() {
return element(by.css('app-root h1')).getText();
}
}
定义了辅助功能后,您可以在编写e2e测试时轻松访问它们。 这是e2e/app.e2e.spec.ts
的示例:
import { AppPage } from './app.po';
describe('angular-tour-of-heroes App', () => {
let page: AppPage;
beforeEach(() => {
page = new AppPage();
});
it('should display welcome message', () => {
page.navigateTo();
expect(page.getParagraphText()).toEqual('Welcome to app!');
});
});
要运行此测试,只需执行以下命令:
ng e2e
如果这是您第一次执行此命令,则可能需要Internet连接。 测试完成后,您很可能会收到一条类似以下内容的失败消息:
angular-tour-of-heroes App
✗ should display welcome message
- Expected 'Tour of Heroes' to equal 'Welcome to app!'.
让我们按照以下方法修复错误。 我还添加了一个测试,以确保我们在app-routing.module.ts
指定的重定向有效:
import { AppPage } from './app.po';
import { browser } from 'protractor';
describe('angular-tour-of-heroes App', () => {
let page: AppPage;
beforeEach(() => {
page = new AppPage();
});
it('should redirect to dashboard', async () => {
page.navigateTo();
const url = await browser.getCurrentUrl();
expect(url).toContain('/dashboard');
});
it('should display welcome message', () => {
page.navigateTo();
expect(page.getParagraphText()).toEqual('Tour of Heroes');
});
});
再次运行测试。 现在,我们应该通过测试:
angular-tour-of-heroes App
✓ should redirect to dashboard
✓ should display welcome message
观看e2e
测试运行是一种了不起的感觉。 它使您确信应用程序将在生产中平稳运行。 既然您已经了解了e2e
,现在该继续进行另一项很酷的测试功能了。
代码覆盖率
作为开发人员,我们最大的问题之一是“我们测试了足够的代码吗?” 幸运的是,我们拥有可以生成“代码覆盖率”的工具来确定要测试多少代码。 要生成报告,只需运行以下命令:
ng test --watch=false --code-coverage
Coverage文件夹将在Angular项目的根目录中创建。 浏览该文件夹,您将找到index.html
。 使用网络浏览器打开它。 您应该会看到以下内容:
我不会在这里详细介绍,但是您可以看到有些类已经过完全测试,而另一些还没有完全测试过。 由于时间和资源的可用性,通常并非总是可能实现100%的测试覆盖率。 但是,您可以与您的团队一起决定最小的数量。 要指定最小值,请使用karma.conf
来配置代码覆盖率设置,如下所示:
coverageIstanbulReporter: {
reports: [ 'html', 'lcovonly' ],
fixWebpackSourcePaths: true,
thresholds: {
statements: 80,
lines: 80,
branches: 80,
functions: 80
}
}
上面的阈值指定了至少80%的单元测试范围。
其他实用程序
现在,我们已经介绍了Angular测试的基础知识。 但是,我们可以通过进一步执行一些步骤来提高代码质量。
1.棉绒
Angular带有执行代码整理的工具。 只需执行以下代码即可对您的项目进行检查:
ng lint
此命令将发出有关代码的警告-例如,在您忘记使用分号或使用太多空格的地方。 该命令还将帮助您识别未使用的代码和语句中的某些错误。 通常使用此命令将确保团队中的每个人都使用一致的样式编写代码。 您可以在tslint.json
文件中进一步自定义lint选项。
2.智能代码编辑器
在代码编辑器和IDE方面,我个人最喜欢的是Atom和Sublime Text 。 但是,我最近发现了Visual Studio Code ,它具有更吸引人的功能。 它是一个免费的代码编辑器,可以在Windows,macOS和Linux中运行。 它从Atom那里借鉴了很多东西,除了它还有我想强调的其他功能:
- 智能感知
- 突出显示错误
- 现代角度扩展
当前,在VSCode中内置了Atom和Sublime Text都没有这些功能。 您只需要安装所需的语言扩展名。 键入代码时,Intellisense功能会为您列出选项。 就像自动完成一样,但是具有语法正确选项的特定列表。 使用此功能,很难犯语法错误。 您还可以查看函数的文档,从而可以查看返回类型和所需的输入。
Visual Studio Code还具有适当的错误突出显示功能。 它不仅检查语法错误,而且确保分配具有正确的类型。 例如,如果您尝试将数组分配给Observable函数的结果,则会为您突出显示错误。 VSCode还具有与Angular 5兼容的Angular扩展。
拥有一个IDE,可以在键入时检查您的代码是否有错误,这对于提高生产力非常有用。 它可以帮助您减少花费在纠正错误上的时间。 可能还有其他代码编辑器可以完成相同的任务,但是现在,我建议为Angular项目使用Visual Studio Code。
3.持续整合
持续集成(CI)是自动化测试和构建的过程。 作为开发人员,我们经常孤立地工作几个星期或更长时间。 当我们将更改合并到master分支时,会产生许多错误和冲突。 这可能需要很多时间才能解决。
CI鼓励开发人员编写测试并经常以较小的位数提交任务。 CI服务器将自动构建并运行测试,以帮助开发人员及早发现错误,从而减少冲突和问题。 Angular开发人员可以使用许多CI解决方案。 查看SitePoint关于在Travis上测试Jasmine和Karma的教程。
结语
我们可以访问有关自动化测试的大量信息,以及用于测试驱动的开发的框架,这些信息可以帮助我们编写测试。 但是,有两个原因导致我们不总是编写测试:
- 不要为新应用编写测试。 该项目的范围将Swift变化,具体取决于客户的需求或市场的React。
- 编写测试除了实现功能外还需要更多时间。 当功能范围更改时,还需要时间来维护。 如果您的预算很低,可以跳过编写测试。 对您拥有的资源要切实可行。
因此,剩下的问题是什么时候该编写测试。 这里有一些指针:
- 您已经完成了原型阶段,并确定了应用程序的核心功能。
- 您的项目有足够的资金。
现在,假设您已决定强制执行TDD,则有很多好处可以收获:
- 编写可以测试的代码意味着您正在编写质量更高的代码。
- 作为开发人员,您将更有信心将最新版本发布到生产环境中。
- 编写测试是记录代码的一种方式。 这意味着未来的开发人员将可以更轻松地升级遗留代码。
- 您无需雇用人员进行质量控制,因为CI服务器将为您完成这项工作。
如果您决定完全跳过产品就绪应用程序的测试,请准备在将来面对生气和失望的客户。 错误的数量将随着代码库大小的增加而呈指数增长。
希望这对您的Angular测试有帮助。 如果您想了解更多信息,建议您首先使用Angular 5官方文档。 除非另有说明,否则大多数信息都针对较旧的Angular版本。
让我们知道您在Angular测试中有任何有趣的提示!
翻译自: https://www.sitepoint.com/angular-testing-introduction/
x:12 y:9,求角度