跳到主要内容
版本:v6

测试

当一个@betway东盟体育appionic /角应用程序是使用Ionic CLI生成的,它会自动设置为单元测试和应用程betway东盟体育app序的端到端测试。这和Angular CLI使用的设置是一样的。请参阅Angular测试指南查看关于测试Angular应用程序的详细信息。

测试的原则

在测试应用程序时,最好记住测试可以显示系统中是否存在缺陷。然而,不可能证明任何非平凡系统是完全没有缺陷的。因此,测试的目标不是验证代码是否正确,而是在代码中发现问题。这是一个微妙但重要的区别。

如果我们开始证明代码是正确的,我们更有可能坚持通过代码的快乐路径。如果我们开始寻找问题,我们更有可能更全面地练习代码,并发现潜伏在那里的bug。

最好从一开始就开始测试应用程序。这样就可以在过程的早期发现缺陷,此时缺陷更容易修复。这还允许在向系统添加新特性时自信地重构代码。

单元测试

单元测试测试一个独立于系统其余部分的代码单元(组件、页面、服务、管道等)。隔离是通过注入模拟对象来代替代码的依赖项来实现的。模拟对象允许测试对依赖项的输出进行细粒度控制。模拟还允许测试确定调用了哪些依赖项以及向它们传递了什么。

编写良好的单元测试的结构是这样的:代码单元及其包含的特性是通过描述的描述()回调。代码单元的需求及其特性是通过它()回调。当描述为描述()而且它()回调函数被读取,它们作为一个短语是有意义的。当描述为嵌套时描述()S和final它()连接在一起,它们形成一个完整描述测试用例的句子。

由于单元测试孤立地执行代码,因此它们快速、健壮,并允许高度的代码覆盖。

使用模拟

单元测试孤立地测试代码模块。为了实现这一点,我们建议使用Jasmine (https://jasmine.github.io/).Jasmine在测试时创建模拟对象(Jasmine称之为“间谍”)来代替依赖项。当使用模拟对象时,测试可以控制调用该依赖项返回的值,使当前测试独立于对依赖项所做的更改。这也使得测试设置更容易,允许测试只关注被测模块中的代码。

使用模拟还允许测试查询模拟,以确定是否调用了它以及如何通过toHaveBeenCalled *函数的集合。对这些函数的测试应该尽可能具体,有利于对的调用toHaveBeenCalledTimes通过呼叫toHaveBeenCalled当测试方法是否被调用时。这是期望(mock.foo) .toHaveBeenCalledTimes (1)期望(mock.foo) .toHaveBeenCalled ().当测试某个东西没有被调用时,应该遵循相反的建议(期望(mock.foo) .not.toHaveBeenCalled ()).

在Jasmine中有两种创建模拟对象的常用方法。可以从头构造模拟对象jasmine.createSpy而且jasmine.createSpyObj或者间谍可以安装到现有的对象使用spyOn ()而且spyOnProperty ()

使用jasmine.createSpy而且jasmine.createSpyObj

jasmine.createSpyObj从头使用创建时定义的一组模拟方法创建完整的模拟对象。这很有用,因为它非常简单。测试中不需要构造或注入任何东西。使用此函数的缺点是它允许创建可能与实际对象不匹配的对象。

jasmine.createSpy类似,但它创建了一个独立的模拟函数。

使用spyOn ()而且spyOnProperty ()

spyOn ()在现有对象上安装间谍。使用这种技术的优点是,如果试图监视对象上不存在的方法,则会引发异常。这可以防止测试模拟不存在的方法。缺点是测试开始时需要一个完全成形的对象,这可能会增加所需的测试设置量。

spyOnProperty ()类似,区别在于它监视的是属性而不是方法。

总体测试结构

单元测试包含在规范带一个的文件规范每个实体(组件、页面、服务、管道等)的文件。的规范文件与它们正在测试的源代码并排存在,并以其命名。例如,如果项目有一个名为WeatherService的服务,则该服务的代码位于一个名为weather.service.ts在一个名为weather.service.spec.ts.这两个文件都在同一个文件夹里。

规范文件本身包含一个描述调用,它定义了整个测试。嵌套在它里面的是其他描述定义主要功能区域的调用。每一个描述调用可以包含设置和拆卸代码(通常通过beforeEach而且afterEach调用),更描述调用形成功能的分层分解,以及定义单个测试用例的调用。

描述而且调用还包含描述性文本标签。在格式良好的测试中,描述而且调用与它们的标签结合在一起,为每个测试用例执行适当的短语和完整的标签,通过组合描述而且标签,创造一个完整的句子。

例如:

描述“计算”= >
描述“分”= >
“正确计算4 / 2”= >
“懦夫拒绝除零”= >
...


描述“乘”= >
...


描述调用声明计算服务正在被测试,内部描述调用准确地声明正在测试的功能,而调用声明测试用例是什么。当运行时,每个测试用例的完整标签都是一个有意义的句子(计算除法懦夫拒绝除零)。

页面和组件

页面只是Angular的组件。因此,页面和组件都使用Angular的组件测试指导方针。

由于页面和组件同时包含TypeScript代码和HTML模板标记,因此可以同时执行组件类测试和组件DOM测试。当创建一个页面时,生成的模板测试看起来像这样:

进口CUSTOM_ELEMENTS_SCHEMA“@angular /核心”
进口异步ComponentFixture试验台“@angular /核心/测试”

进口TabsPage”。/ tabs.page '

描述“TabsPage”= >
组件TabsPage
夹具ComponentFixture<TabsPage>

beforeEach异步= >
试验台configureTestingModule
声明TabsPage
模式CUSTOM_ELEMENTS_SCHEMA
compileComponents


beforeEach= >
夹具试验台createComponentTabsPage
组件夹具componentInstance
夹具detectChanges


“应该创建”= >
预计组件toBeTruthy


在进行组件类测试时,使用via定义的组件对象访问组件对象component = fixture.componentInstance;.这是组件类的一个实例。在进行DOM测试时,fixture.nativeElement属性被使用。这是实际的HTMLElement该组件允许测试使用标准的HTML API方法,例如HTMLElement.querySelector以便检查DOM。

服务

服务通常分为两大类:执行计算和其他操作的实用服务,以及主要执行HTTP操作和数据操作的数据服务。

基本服务测试

测试大多数服务的建议方法是实例化服务,并为该服务具有的任何依赖项手动注入模拟。这样,代码就可以单独测试。

假设有一个服务,该服务具有一种方法,它接受一组工卡并计算净工资。我们还假设税收计算是通过当前服务所依赖的另一个服务处理的。这个工资单服务可以这样测试:

进口PayrollService”。/ payroll.service '

描述“PayrollService”= >
服务PayrollService
taxServiceSpy

beforeEach= >
taxServiceSpy茉莉花createSpyObj“TaxService”
federalIncomeTax0
stateIncomeTax0
社会保障0
医疗保险0

服务PayrollServicetaxServiceSpy


描述“净薪酬计算”= >
...


这允许测试通过模拟设置控制各种税收计算返回的值,例如taxServiceSpy.federalIncomeTax.and.returnValue (73.24).这使得“净支付”测试独立于税收计算逻辑。当税务代码更改时,只需要更改与税务服务相关的代码和测试。净收入测试可以继续按原样运行,因为这些测试并不关心税收是如何计算的,只关心价值是否被正确应用。

通过生成服务时使用的脚手架betway东盟体育appIonic g服务名称使用Angular的测试工具,并建立一个测试模块。这样做并不是严格必要的。然而,该代码可以保留,允许手动构建或注入服务:

进口试验台注入“@angular /核心/测试”

进口PayrollService”。/ payroll.service '
进口TaxService”。/ tax.service '

描述“PayrolService”= >
taxServiceSpy

beforeEach= >
taxServiceSpy茉莉花createSpyObj“TaxService”
federalIncomeTax0
stateIncomeTax0
社会保障0
医疗保险0

试验台configureTestingModule
供应商PayrollService提供TaxServiceuseValuetaxServiceSpy



“在注射的地方做一些测试”注入PayrollService服务PayrollService= >
预计服务toBeTruthy


“在手动构建的地方进行一些测试”= >
常量服务PayrollServicetaxServiceSpy
预计服务toBeTruthy


测试HTTP数据服务

大多数执行HTTP操作的服务都会使用Angular的HttpClient服务来执行这些操作。对于这样的测试,建议使用Angular的HttpClientTestingModule.有关这个模块的详细文档,请参阅Angular的文档Angular的HTTP请求测试指南。

这样一个测试的基本设置如下:

进口HttpBackendHttpClient“@angular /共同/ http”
进口HttpTestingControllerHttpClientTestingModule“@angular /共同/ http /测试”
进口试验台注入“@angular /核心/测试”

进口IssTrackingDataService”。/ iss-tracking-data.service '

描述“IssTrackingDataService”= >
httpClientHttpClient
httpTestingControllerHttpTestingController
issTrackingDataServiceIssTrackingDataService

beforeEach= >
试验台configureTestingModule
进口HttpClientTestingModule
供应商IssTrackingDataService


httpClient试验台得到HttpClient
httpTestingController试验台得到HttpTestingController
issTrackingDataServiceIssTrackingDataServicehttpClient


“存在”注入IssTrackingDataService服务IssTrackingDataService= >
预计服务toBeTruthy


描述“位置”= >
“现在知道国际空间站的位置了”= >
issTrackingDataService位置订阅x= >
预计xtoEqual经度-138.1719纬度44.4423

常量要求的事情httpTestingControllerexpectOne“http://api.open-notify.org/iss-now.json”
预计要求的事情请求方法toEqual“得到”
要求的事情冲洗
iss_position经度“-138.1719”纬度“44.4423”
时间戳1525950644
消息“成功”

httpTestingController验证



管道

管道类似于具有特定定义接口的服务。它是一个包含一个公共方法的类,变换,它操作输入值(和其他可选参数),以创建在页面上呈现的输出。要测试管道:实例化管道,调用transform方法,并验证结果。

作为一个简单的例子,让我们看看一个以a为参数的管道对象并格式化名称。为了简单起见,我们设aidfirstName,middleInitial.管道的需求是将名称打印为“Last, First M.”,以处理名、姓或中间首字母不存在的情况。这样的测试可能是这样的:

进口NamePipe”。/ name.pipe '

进口“. . / . . /模型/人”

描述“NamePipe”= >
NamePipe
testPerson

beforeEach= >
NamePipe
testPerson
id42
firstName“道格拉斯。”
“亚当斯”
middleInitial“N”



“存在”= >
预计toBeTruthy


'正确格式化全名'= >
预计变换testPersontoBeEqual亚当斯,道格拉斯·N。


“句柄没有中间首字母”= >
删除testPersonmiddleInitial
预计变换testPersontoBeEqual“亚当斯,道格拉斯。”


没有名字的句柄= >
删除testPersonfirstName
预计变换testPersontoBeEqual“亚当斯N。”


“没有姓氏的句柄”= >
删除testPerson
预计变换testPersontoBeEqual“道格拉斯N。”


通过在使用管道的组件和页面中进行DOM测试来测试管道也是有益的。

端到端测试

端到端测试用于验证应用程序作为一个整体工作,并且通常包括到活动数据的连接。单元测试关注于隔离的代码单元,因此允许对应用程序逻辑进行低级测试,而端到端测试关注于各种用户故事或使用场景,提供对整个应用程序数据流的高级测试。单元测试试图发现应用程序逻辑中的问题,而端到端测试试图发现当这些单独的单元一起使用时发生的问题。端到端测试揭示了应用程序整体架构中的问题。

由于端到端测试使用用户描述,并将应用程序作为一个整体而不是单个代码模块覆盖,因此端到端测试存在于项目中与主应用程序本身的代码不同的应用程序中。大多数端到端测试通过自动化用户与应用程序的交互并检查DOM以确定这些交互的结果来进行操作。

测试结构

当一个@betway东盟体育appionic /角应用程序时,将生成默认的端到端测试应用程序e2e文件夹中。此应用程序使用量角器来控制浏览器和茉莉花来组织和执行测试。应用程序最初由四个文件组成:

  • protractor.conf.js-量角器配置文件
  • tsconfig.e2e.json-测试应用程序的特定TypeScript配置
  • src / app.po.ts-一个页面对象,包含导航应用程序、查询DOM中的元素和操作页面上元素的方法
  • src / app.e2e-spec.ts-一个测试脚本

页面对象

端到端测试通过自动化用户与应用程序的交互、等待应用程序响应和检查DOM以确定交互的结果来进行操作。这涉及到大量DOM操作和检查。如果这些都是手动完成的,那么测试将非常脆弱,难以读取和维护。

Page对象在TypeScript类中封装了单个页面的HTML,提供了测试脚本用来与应用程序交互的API。在页面对象中封装DOM操作逻辑使测试更具可读性,更容易进行推理,从而降低了测试的维护成本。创建精心制作的页面对象是创建高质量和可维护的端到端测试的关键。

基页对象

许多测试依赖于诸如等待页面可见、在输入中输入文本以及单击按钮等操作。用于完成此操作的方法仅与用于获得适当的DOM元素更改的CSS选择器保持一致。因此,将此逻辑抽象为可由其他页面对象使用的基类是有意义的。

下面是一个示例,它实现了一些所有页面对象都需要支持的基本方法。

进口浏览器通过元素ExpectedConditions“量角器”

出口PageObjectBase
私人路径字符串
受保护的标签字符串

构造函数标签字符串路径字符串
标签标签
路径路径


负载
返回浏览器得到路径


rootElement
返回元素通过css标签


waitUntilInvisible
浏览器等待ExpectedConditionsinvisibilityOfrootElement3000


waitUntilPresent
浏览器等待ExpectedConditionspresenceOfrootElement3000


waitUntilNotPresent
浏览器等待ExpectedConditionsExpectedConditionspresenceOfrootElement3000


waitUntilVisible
浏览器等待ExpectedConditionsvisibilityOfrootElement3000


getTitle
返回元素通过css$ {标签ion-titlegetText


受保护的enterInputText选取字符串文本字符串
常量埃尔元素通过css$ {标签$ {选取
常量可使埃尔元素通过css“输入”
可使sendKeys文本


受保护的enterTextareaText选取字符串文本字符串
常量埃尔元素通过css$ {标签$ {选取
常量可使埃尔元素通过css“文本区域”
可使sendKeys文本


受保护的clickButton选取字符串
常量埃尔元素通过css$ {标签$ {选取
浏览器等待ExpectedConditionselementToBeClickable埃尔
埃尔点击


页面的抽象

应用程序中的每个页面都有自己的页面对象类,该类抽象了该页上的元素。如果使用基页对象类,则创建页对象主要涉及为特定于该页的元素创建自定义方法。通常,这些自定义元素利用基类中的方法来执行所需的工作。

下面是一个简单但典型的登录页面的示例页面对象。注意,许多方法,例如enterEMail (),调用基类中执行大部分工作的方法。

进口浏览器通过元素ExpectedConditions“量角器”
进口PageObjectBase”。/ base.po '

出口LoginPage扩展PageObjectBase
构造函数
超级“app-login”/登录的


waitForError
浏览器等待ExpectedConditionspresenceOf元素通过css' . error '3000


getErrorMessage
返回元素通过css' . error 'getText


enterEMail电子邮件字符串
enterInputText“# email-input”电子邮件


enterPassword密码字符串
enterInputText“#密码输入”密码


clickSignIn
clickButton“# signin-button”


测试脚本

与单元测试类似,端到端测试脚本由嵌套组成描述()而且它()功能。对于端到端测试,描述()函数通常表示特定的场景它()函数表示在该场景中执行操作时应用程序应该显示的特定行为。

中使用的标签也类似于单元测试描述()而且它()函数在使用“describe”或“it”以及连接在一起形成完整的测试用例时都应该是有意义的。

下面是一个示例端到端测试脚本,用于测试一些典型的登录场景。

进口AppPage“. . /页面对象/页面/ app.po”
进口AboutPage“. . /页面对象/页面/ about.po”
进口CustomersPage“. . /页面对象/页面/ customers.po”
进口LoginPage“. . /页面对象/页面/ login.po”
进口MenuPage“. . /页面对象/页面/ menu.po”
进口TasksPage“. . /页面对象/页面/ tasks.po”

描述“登录”= >
常量关于AboutPage
常量应用程序AppPage
常量客户CustomersPage
常量登录LoginPage
常量菜单MenuPage
常量任务TasksPage

beforeEach= >
应用程序负载


描述“登录前”= >
“显示登录屏幕”= >
预计登录rootElementisDisplayedtoEqual真正的


“允许应用内导航about”= >
菜单clickAbout
关于waitUntilVisible
登录waitUntilInvisible


“不允许在应用程序内导航任务”= >
菜单clickTasks
应用程序waitForPageNavigation
预计登录rootElementisDisplayedtoEqual真正的


“不允许用户在应用程序内导航”= >
菜单clickCustomers
应用程序waitForPageNavigation
预计登录rootElementisDisplayedtoEqual真正的


'如果登录失败显示错误消息'= >
登录enterEMail“test@test.com”
登录enterPassword“假的”
登录clickSignIn
登录waitForError
预计登录getErrorMessagetoEqual'密码无效或用户没有密码。'


'如果登录成功,将导航到任务页面'= >
登录enterEMail“test@test.com”
登录enterPassword“测试”
登录clickSignIn
任务waitUntilVisible



描述“一旦登录”= >
beforeEach= >
任务waitUntilVisible


“允许导航到客户页面”= >
菜单clickCustomers
客户waitUntilVisible
任务waitUntilInvisible


“允许导航到关于页面”= >
菜单clickAbout
关于waitUntilVisible
任务waitUntilInvisible


“允许导航回任务页面”= >
菜单clickAbout
任务waitUntilInvisible
菜单clickTasks
任务waitUntilVisible



配置

默认配置使用相同的方法environment.ts用于开发的文件。为了更好地控制端到端测试所使用的数据,为测试创建一个特定的环境并将该环境用于测试通常是有用的。本节将展示创建此配置的一种可能方法。

测试环境

设置测试环境涉及创建一个新的环境文件,该文件使用专用的测试后端,更新angular.json文件来使用该环境,并修改e2e脚本。package.json要指定测验环境。

创建environment.e2e.ts文件

environment.ts而且environment.prod.ts文件通常用于存储诸如应用程序后端数据服务的基本URL之类的信息。创建一个environment.e2e.ts这提供了相同的信息,只是连接到专门用于测试的后端服务,而不是开发或生产后端服务。这里有一个例子:

出口常量环境
生产
databaseURL“https://e2e-test-api.my-great-app.com”
projectId“my-great-app-e2e”

修改angular.json文件

angular.json文件需要修改才能使用此文件。这是一个分层的过程。按照下面列出的xpath添加所需的配置。

/项目/应用程序/建筑师/构建/配置被称为测验执行文件替换:

“测试”
“fileReplacements”

“替换”“src /环境/ environment.ts”
”与““src /环境/ environment.e2e.ts”



/项目/ app /建筑师/服务/配置被称为测验将浏览器目标指向测验构建上面定义的配置。

“测试”
“browserTarget”“应用程序:构建:测试”

/项目/ app-e2e /建筑师/ e2e /配置被称为测验将开发服务器目标指向测验服务上面定义的配置。

“测试”
“devServerTarget”“应用程序服务:测试”

修改package.json文件

修改package.json存档以便NPM运行e2e使用测验配置。

“脚本”
“e2e”"ng e2e——configuration=test"
“棉絮”“ng线头”
“ng”“ng”
“开始”“ng服务”
“测试”“ng测试”
“测试:开发”"ng test——浏览器=ChromeHeadlessCI"
“测试:ci”"ng test——no-watch——浏览器=ChromeHeadlessCI"

测试清理

如果端到端测试以任何方式修改数据,那么在测试完成后将数据重置为已知状态是有帮助的。一种方法是:

  1. 创建执行清理的端点。
  2. 添加一个onCleanUp ()函数配置对象导出的protractor.conf.js文件。

这里有一个例子:

onCleanUp
常量axios需要“axios”
返回axios
帖子
“https://e2e-test-api.my-great-app.com/purgeDatabase”


然后res= >
控制台日志res数据

犯错= >控制台日志犯错

Baidu