使用 Protractor 在 Angular 应用程序中进行端到端(E2E)测试





5.00/5 (1投票)
如何为我们的 Angular 应用程序创建端到端测试
引言
在本文中,我们将学习如何为我们的 Angular 应用创建端到端测试 (e2e)。我们将使用一个现有的端到端测试框架,即 Protractor。Protractor 会在真实的浏览器中运行您的测试,就像您的用户执行操作一样。我将使用一个在我 GitHub 个人资料中可用的现有应用程序。源代码部分也有。请与我分享您的反馈。希望您喜欢这篇文章。让我们开始编码吧。
源代码
源代码可以在 这里 找到。请在开始之前克隆此存储库。
端到端测试的重要性
你们中的一些人可能已经开始为您的应用程序编写端到端测试,并且可能知道它的重要性。在这里,我将列出端到端测试的关键好处。
- 端到端测试会测试完整的流程或操作。例如,一个完整的登录过程可以视为一个端到端测试。基本上,它会测试一个特定的功能。
- 它不像单元测试那样提高代码质量。单元测试是一个不同的主题,端到端测试和单元测试是完全不同的。
- 正如我之前所说,端到端测试在浏览器中运行测试,因此它会实时测试您的应用程序,并包含一些真实数据。
- 您可以轻松地找出,是否由于您最近的更改或实现而导致任何功能损坏。
基本概述
如果您已经克隆了应用程序,您应该会在应用程序代码中看到一个名为 e2e 的文件夹,请打开该文件夹。您可以看到以下三个文件:
- tsconfig.e2e.json
- app.po.ts
- app.e2e-spec.ts
这里的 tsconfig.e2e.json 是配置文件,如果您打开该文件,您会看到该文件是从 tsconfig.json 扩展而来的。
{
"extends": "../tsconfig.json",
"compilerOptions": {
"outDir": "../out-tsc/e2e",
"baseUrl": "./",
"module": "commonjs",
"target": "es5",
"types": [
"jasmine",
"jasminewd2",
"node"
]
}
}
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();
}
}
正如您所见,在第一行,我们从 protractor 导入了 browser
、by
和 element
。
browser
用于与浏览器交互by
用于按 CSS 或任何其他函数查找元素element
用于转换选定的元素
在这一行,element(by.css('app-root h1')).getText()
,正如您已经猜到的,我们只是使用选择器 'app-root h1
' 来查找一个元素。
app.e2e-spec.ts 是测试的容器。我们将在其中编写所有测试。
import { AppPage } from './app.po'; describe('my-angular5-app App', () => { let page: AppPage; beforeEach(() => { page = new AppPage(); }); it('should display welcome message', () => { page.navigateTo(); expect(page.getParagraphText()).toEqual('Welcome to ng5!'); }); });
我们首先要做的是导入页面,在这种情况下是 AppPage
。如果您已经使用 jasmine 编写了任何 单元测试用例,这将非常容易。如果您不确定如何编写单元测试,我建议您访问 此链接。
导入页面后,我们在 beforeEach
函数中声明一个对象并用 AppPage
实例初始化它,以便在每个测试运行之前可以执行代码。
在我们第一个测试中,我们只是通过调用 page.getParagraphText()
从我们的 page
对象获取值,来确认标题是 'Welcome to app
'。
创建登录组件
正如你们都知道的,一个组件默认会有两个文件:
- login.component.html
- login.component.ts
login.component.html
让我们为我们的组件编写一些 HTML 代码。
<div class="container" style="margin-top:100px;">
<div class="row justify-content-center align-items-center">
<div class="col-lg-4 col-sm-4 center-block ">
<mat-card>
<mat-card-header>
<img mat-card-avatar src="../../../assets/images/App-login-manager-icon.png">
<mat-card-title>Login here</mat-card-title>
<mat-card-subtitle>Trust us for your data, and sign up</mat-card-subtitle>
</mat-card-header>
<mat-card-content>
<div class="signup-fields">
<form id="loginForm"[formGroup]="form" (ngSubmit)="login()">
<div class="form-group">
<input name="email" class="form-control"
matInput type="email" placeholder="Email" formControlName="email" />
</div>
<div class="form-group">
<input name="password" class="form-control"
matInput type="password" placeholder="Password"
formControlName="password" />
</div>
<div>
<button id="btnSubmit" mat-raised-button type="submit"
color="primary">Login</button>
</div>
</form>
</div>
</mat-card-content>
</mat-card>
</div>
</div>
</div>
login.component.ts
import { Component, OnInit } from '@angular/core';
import { FormBuilder, Validators } from '@angular/forms';
import { Router } from '@angular/router';
import { AuthService } from '../auth.service';
@Component({
selector: 'app-login',
templateUrl: './login.component.html',
styleUrls: ['./login.component.css']
})
export class LoginComponent implements OnInit {
form;
constructor(private fb: FormBuilder,
private myRoute: Router,
private auth: AuthService) {
this.form = fb.group({
email: ['', [Validators.required, Validators.email]],
password: ['', Validators.required]
});
}
ngOnInit() {
}
login() {
if (this.form.valid) {
this.auth.sendToken(this.form.value.email)
this.myRoute.navigate(["home"]);
}
}
}
如果您运行应用程序,您会看到,只有当我们为字段提供相关值时,我们才会接受表单,否则表单将无效。在下一步中,我们将为这个功能编写端到端测试。听起来不错吧?
为登录组件编写端到端测试
首先,让我们创建以下两个文件:
- login.po.ts
- login.e2e-spec.ts
现在让我们在 login.po.ts 中定义我们的页面和一些函数。
设置 login.po.ts
打开文件并像前面一样编写一些代码。
import { browser, by, element } from 'protractor';
export class LoginPage {
navigateTo(){
return browser.get('/login');
}
}
现在我们将编写代码来查找电子邮件和密码文本框。
getEmailTextbox() {
return element(by.name('email'));
}
getPasswordTextbox() {
return element(by.name('password'));
}
设置 login.e2e-spec.ts
在开始编写测试之前,是时候设置我们的 spec 文件了。
import { LoginPage } from './login.po';
describe('Login tests', () => {
let page: LoginPage;
beforeEach(() => {
page = new LoginPage();
page.navigateTo();
});
});
我们已经导入了我们的 LoginPage
并对其进行了初始化。现在是时候编写测试了。
it('Login form should be valid', () => {
page.getEmailTextbox().sendKeys('info@sibeeshpassion.com');
page.getPasswordTextbox().sendKeys('1234');
let form = page.getForm().getAttribute('class');
expect(form).toContain('ng-valid');
});
在这里,我们所做的是,使用 sendKeys
函数设置文本框的值,然后查找我们表单的 class
属性,以便我们可以检查它是否有效。如果表单有效,表单将具有 class
ng-valid
,否则,它将具有 ng-invalid
类。
运行端到端测试
运行端到端测试就像从日志中掉下来一样容易。由于我们使用 Angular CLI,我们所要做的就是运行命令 ng e2e
。这将在我们的 package.json 文件中设置。
"scripts": {
"ng": "ng",
"start": "ng serve",
"build": "ng build",
"test": "ng test",
"lint": "ng lint",
"e2e": "ng e2e"
}
现在让我们运行 ng e2e
。
PS F:\My Projects\ng5> ng e2e
如果一切顺利,您的应用程序应该会在浏览器中打开并测试该功能。您还将收到一条消息:“Chrome 正在被自动化测试软件控制”。
在您的终端控制台中,您应该会看到一条消息,说明所有测试都已通过。
编写更多测试
让我们编写更多测试来检查其他功能。
检查表单是否无效
要检查表单是否无效,我们需要向表单传递一些无效数据。最终的测试应如下所示:
it('Login form should be invalid', () => {
page.getEmailTextbox().sendKeys('');
page.getPasswordTextbox().sendKeys('');
let form = page.getForm().getAttribute('class');
expect(form).toContain('ng-invalid');
});
检查值是否已保存到本地存储
您可能已经查看了我们在应用程序中单击 **Login** 按钮时执行的功能。目前,我们只是将电子邮件值保存到本地存储。下面是单击 **Login** 按钮时调用的函数。
login() {
if (this.form.valid) {
this.auth.sendToken(this.form.value.email)
this.myRoute.navigate(["home"]);
}
}
这是我们 AuthService
中的 sendToken
方法。
sendToken(token: string) {
localStorage.setItem("LoggedInUser", token)
}
现在,我们将为此功能编写自动化测试。首先,让我们在 login.po.ts 中添加一个返回 **Submit** 按钮的函数。
getSubmitButton() {
return element(by.css('#btnSubmit'));
}
现在,像这样编写测试:
it('Should set email value to local storage', () => {
page.getEmailTextbox().sendKeys('info@sibeeshpassion.com');
page.getPasswordTextbox().sendKeys('1234');
page.getSubmitButton().click();
let valLocalStorage = browser.executeScript
("return window.localStorage.getItem('LoggedInUser');");
expect(valLocalStorage).toEqual('info@sibeeshpassion.com');
});
正如您所看到的,我们实际上向表单设置了一些有效数据,并触发了我们按钮的单击事件,电子邮件文本框的值被保存到 localStorage。在我们的测试中,我们通过执行脚本 browser.executeScript("return window.localStorage.getItem('LoggedInUser');")
来检查 localStorage
的值。如果一切正常,我们应该会看到如下输出。
结论
非常感谢您的阅读。我很快就会带着一篇关于同一主题的帖子回来。我是否遗漏了您认为需要的东西?您是否觉得这篇文章有用?希望您喜欢这篇文章。请分享您宝贵的建议和反馈。
现在轮到你了。你有什么想法?
没有评论的博客算不上博客,但请尽量保持主题相关。如果您有一个与本文无关的问题,最好将其发布到 C# Corner、Code Project、Stack Overflow、ASP.NET 论坛,而不是在此处评论。请在下面的评论部分发布您的问题,我会尽力提供帮助。
历史
- 2018年7月18日:初始版本