许多类都有在使用配置对象创建(实例化)类时使用的快捷名称。快捷名称称为别名
(如果类扩展 Ext.Component,则称为xtype
)。对于可应用的类,别名/xtype 会列在类名称旁边,以便快速参考。
框架类或其成员可以指定为私有
或受保护
。否则,类/成员为公共
。公共
、受保护
和私有
是访问描述符,用于传达如何以及何时应该使用类或类成员。
公共类和类成员可供任何其他类或应用程序代码使用,并且可以依赖它们在主要产品版本中保持稳定和持久。公共类和成员可以通过子类安全地扩展。
受保护类成员是稳定的公共
成员,旨在供拥有类或其子类使用。受保护成员可以通过子类安全地扩展。
私有类和类成员由框架内部使用,不打算供应用程序开发人员使用。私有类和成员可能会在任何时候更改或从框架中省略,而无需另行通知,并且不应在应用程序逻辑中依赖它们。
静态
标签。*参见下文的静态。下面是一个示例类成员,我们可以对其进行剖析以显示类成员的语法(在本例中,是从 Ext.button.Button 类查看的 lookupComponent 方法)。
我们来看看成员行中的每一部分
lookupComponent
)( item )
)Ext.Component
)。对于不返回 undefined
以外任何内容的方法,可以省略此项,或者可能显示用正斜杠 /
分隔的多个可能值,表示返回的内容可能取决于方法调用的结果(即,如果 get 方法调用成功,方法可能会返回一个组件,如果失败,则返回 false
,将显示为 Ext.Component/Boolean
)。PROTECTED
- 请参阅下面的标志部分)Ext.container.Container
)。如果成员源自当前类,则源类将显示为蓝色链接,如果它从祖先或混合类继承,则显示为灰色。查看源
)item : Object
)列出。undefined
,则“返回”部分将记录返回的类或对象类型以及描述(在本例中为 Ext.Component
)自 3.4.0 起可用
- 在示例中未显示)默认为:false
)API 文档使用许多标志来进一步传达类成员的功能和意图。标签可以用文本标签、缩写或图标表示。
classInstance.method1().method2().etc();
false
,则标记为可预防的事件不会触发- 表示框架类
- 单例框架类。*有关详细信息,请参阅单例标志
- 组件类型框架类(Ext JS 框架中任何扩展 Ext.Component 的类)
- 表示类、成员或指南在当前查看的版本中是新的
- 表示类型为 config
的类成员
- 表示类型为 property
的类成员
- 表示类型为 method
的类成员
- 表示类型为 event
的类成员
- 表示类型为 theme variable
的类成员
- 表示类型为 theme mixin
的类成员
- 表示类、成员或指南在当前查看的版本中是新的
在 API 文档页面上类名称正下方是一行按钮,对应于当前类拥有的成员类型。每个按钮按类型显示成员数(此计数在应用筛选器时更新)。单击按钮将导航到该成员部分。将鼠标悬停在成员类型按钮上将显示一个弹出菜单,其中包含该类型的所有成员,以便快速导航。
与类配置选项相关的 Getter 和 Setter 方法将显示在方法部分以及 API 文档和成员类型菜单的配置部分中,它们与之一起工作的配置正下方。Getter 和 Setter 方法文档将位于配置行中,以便于参考。
您的页面历史记录保存在本地存储中,并显示在顶部标题栏正下方(使用可用空间)。默认情况下,仅显示与您当前正在查看的产品/版本匹配的搜索结果。您可以通过单击历史记录栏右侧的 按钮并选择“全部”单选选项来扩展显示内容。这将在历史记录栏中显示所有产品/版本的所有近期页面。
在历史记录配置菜单中,您还将看到最近访问的页面列表。结果按“当前产品/版本”和“全部”单选选项进行筛选。单击 按钮将清除历史记录栏以及本地存储中保存的历史记录。
如果在历史记录配置菜单中选择“全部”,则将启用“在历史记录栏中显示产品详细信息”复选框选项。选中后,每个历史页面的产品/版本将与历史记录栏中的页面名称一起显示。将光标悬停在历史记录栏中的页面名称上也将以工具提示的形式显示产品/版本。
可以使用页面顶部的搜索字段搜索 API 文档和指南。
在 API 文档页面上,还有一个筛选器输入字段,它使用筛选器字符串筛选成员行。除了按字符串筛选外,您还可以按访问级别、继承和只读筛选类成员。这是使用页面顶部的复选框完成的。
API 类导航树底部的复选框筛选类列表以包括或排除私有类。
单击空搜索字段将显示您最近 10 次搜索,以便快速导航。
每个 API 文档页面(Javascript 基本类型页面除外)都有一个与该类相关的元数据的菜单视图。此元数据视图将包含以下一个或多个
Ext.button.Button
类有一个备用类名 Ext.Button
)。备用类名通常用于保持向后兼容性。可运行示例(Fiddle)默认在页面上展开。你可以使用代码块左上角的箭头单独折叠和展开示例代码块。你还可以使用页面右上角的切换按钮切换所有示例的折叠状态。切换所有状态将在页面加载之间记住。
类成员默认在页面上折叠。你可以使用成员行左侧的箭头图标展开和折叠成员,或全局使用右上角的展开/折叠所有切换按钮。
在较窄的屏幕或浏览器上查看文档将导致针对较小尺寸优化视图。桌面和“移动”视图之间的主要区别是
可以通过单击 API 文档页面顶部的类名来查看类源。可以通过单击成员行右侧的“查看源”链接来查看类成员的源。
本教程帮助你使用 Sencha WebTestIt 创建你的第一个 UI 测试。你将逐步自动化我们的 Demoshop 示例的部分内容,并且你可以按照本教程创建所有源文件
本教程的资源以 TypeScript、Java 和 Python 提供。
如果你尚未创建新项目,请按照以下说明进行操作
单击欢迎选项卡上的新建项目链接,或转到文件 > 新建项目。
在新建项目对话框中,为你的项目指定一个名称和位置,然后选择你想要使用的脚本语言。
单击保存后,Sencha WebTestIt 将创建你的项目并设置运行测试所需的组件。
注意
你选择的编程语言定义了为你设置的自动化框架。如果你选择 TypeScript,Sencha WebTestIt 将为你生成一个 Protractor 环境。如果你选择 Java,则会设置一个 TestNg 应用程序。如果你选择 Python,Sencha WebTestIt 将生成一个 unittest 环境。
你可以在项目选项卡中检查新生成项目的结构。Sencha WebTestIt 自动为你的测试套件和页面对象创建文件夹。你可以在项目的根目录中看到的用于配置你的测试和设置你的环境以运行它的文件。项目中值得注意的配置文件如下
文件名 | 说明 |
---|---|
.editorconfig |
包含 Sencha WebTestIt 代码编辑器的代码样式设置。 在此处了解有关 editorconfig 设置的更多信息 |
*.endpoints.json |
存储有关将执行测试的端点的信息。 单击此处以阅读有关端点的更多信息 |
webtestit.json |
包含 Sencha WebTestIt 测试项目的特定项目选项。 此处定义的所有设置都限定于单个项目,而不是全局设置,你可以通过主菜单文件 > 首选项 > 用户设置访问全局设置 |
在本教程中,我们将自动化 Demoshop。你可以在 此处 找到它。继续,看看它。
Demoshop 的主页包含不同的部分
1 带有菜单和搜索字段的头区域
2 列出产品的正文区域
Demoshop 包含其他各种页面。对于本教程,搜索产品并将其添加到购物车。让我们创建一些测试用例,然后对其进行自动化
# | 标题 | 说明 |
---|---|---|
1 | 搜索项目 | 假设显示了 Demoshop 当用户输入“Super”作为搜索项目并按 Enter 键时 然后显示“Super Cool Goo”的详细信息页面 并且产品名称等于“Super Cool Goo” 并且价格等于 1,500.00 欧元 |
2 | 将项目添加到购物车 | 假设显示了“Super Cool Goo”的详细信息页面 当用户单击“添加到购物车”按钮时 然后显示确认消息 并且项目计数器显示 1 并且购物车区域中的小计等于产品的价格 |
提示
测试用例说明使用 Gherkin 语法. 这是定义测试用例的一种简单方法。每条语句都包含这三个关键词
- GIVEN 描述当前状态,也称为前提条件
- WHEN 描述用户的操作
- THEN 描述这些操作的结果,也称为断言
这些关键词的组合称为场景。你可以使用逻辑运算符 (and/or) 将任何块中的多个语句链接起来以创建更复杂的场景。
在设计测试用例时,你只描述应用程序的预期行为。任何偏离此行为都是意外的,因此会被视为测试失败。
现在,让我们使用 Sencha WebTestIt 自动化这些测试用例!
要访问测试用例所需的所有元素,你需要为它们创建选择器。选择器被组织到页面对象中。你可以 在此处 阅读有关选择器的更多信息。
由于你还没有任何页面对象文件,因此你需要创建一个
注意
页面对象不仅包含选择器,还包含模拟的用户输入。事实上,强烈建议仅向各个测试用例公开页面对象操作。 这称为页面对象模式,在此处进行了描述。
单击项目树工具栏中的新建页面对象文件。Sencha WebTestIt 在项目的pageobjects
文件夹中创建一个新文件,并提示你对其进行命名。
或者,右键单击pageobjects
文件夹并通过上下文菜单创建文件。命名该文件,如果你使用 TypeScript,则使用HeaderPo.ts
,如果你使用 Java,则使用HeaderPo.java
,如果你使用 Python,则需要使用蛇形大小写(下划线字符,字符之间没有空格),因此页面对象名称应为header_po.py
。
新创建的文件带有两个默认函数open
和getTitle
。页面对象包含 Demoshop 头部中所需的所有选择器和操作。
参考
为了实现更好的可维护性测试,分析网站或应用程序的结构并将其划分到页面对象中至关重要。您可以在本指南第 3 章中阅读有关页面对象的更多信息
现在,按照以下步骤为详情页创建另一个页面对象
pageobjects
文件夹,然后从上下文菜单中选择新建 > 页面对象文件。DetailPagePo.ts
,如果您使用 Java,请将其命名为DetailPagePo.java
。同样,由于我们在 Python 中使用蛇形命名法,因此将新的页面对象命名为detail_page_po.py
。设置好所有选择器后,您现在可以编写自动化框架将执行的一些操作。
让我们从搜索我们的 T 恤开始。在现实世界中,用户会单击搜索输入并输入搜索词。请记住,测试自动化本质上是模拟用户。这就是您将执行完全相同操作的原因。
pageobjects
文件夹中选择HeaderPo
(header_po
) 文件。searchInput
(_search_input
) 拖动到代码选项卡中。insertSearchText
(在 Python 中为insert_search_text
)。生成的函数是一种简单的结构,可以快速入门并节省您必须编写的代码量。
发送文本后,单击 ENTER 键开始搜索。为此,Sencha WebTestIt 会自动将sendKeys
(send_keys
) 参数添加到该函数。您的代码应如下所示
public void insertSearchText(String text) { this.wait.until(ExpectedConditions.visibilityOfElementLocated(this.searchInput)).sendKeys(text, Keys.RETURN); }
def insert_search_text(self, text): self.wait.until(EC.visibility_of_element_located(self._search_input)).send_keys(text) return self
public async insertSearchText(text: string): Promise { await browser.wait(ExpectedConditions.visibilityOf(element(this.searchInput)), browser.allScriptsTimeout, this.searchInput.toString()); await element(this.searchInput).sendKeys(text, Key.ENTER); return this; }
提示
生成的页面对象操作是从模板创建的。您可以根据网站或应用程序的要求自定义模板。阅读更多有关在本指南第 3 章中自定义模板的信息。
从HeaderPo
页面对象中剩余的元素中,您要获取文本。重复上述操作,但这次在弹出菜单中使用获取元素文本选项并返回文本字符串,或复制以下源代码以执行此操作。
public String getCartAmount() { return this.wait.until(ExpectedConditions.visibilityOfElementLocated(this.cartAmount)).getText(); } public String getCartCount() { return this.wait.until(ExpectedConditions.visibilityOfElementLocated(this.cartCount)).getText(); }
def get_cart_amount(self): cart_count_count = self.wait.until(EC.visibility_of_element_located(self._cart_count)).text return cart_count_count def get_cart_count(self): cart_count_text = self.wait.until(EC.visibility_of_element_located(self._cart_count)).text return cart_count_text
public async getCartAmount(): Promise { await browser.wait(ExpectedConditions.visibilityOf(element(this.cartAmount)), browser.allScriptsTimeout, this.cartAmount.toString()); return await element(this.cartAmount).getText(); } public async getCartCount(): Promise { await browser.wait(ExpectedConditions.visibilityOf(element(this.cartCount)), browser.allScriptsTimeout, this.cartCount.toString()); return await element(this.cartCount).getText(); }
干得好!现在从项目的pageobjects
文件夹中选择DetailPagePo
,并实现以下函数
文件名 | 说明 |
---|---|
getProductName |
返回productName 元素的文本。 |
getProductPrice |
返回productPrice 元素的文本。 |
addProductToCart |
单击addToCartButton 。 |
getConfirmationMessage |
返回cartConfirmationMessage 元素的文本。 |
在 Python 中,分别对函数名称使用蛇形命名法
最终,DetailPagePo
中的函数应如下所示
public String getProductName() { return this.wait.until(ExpectedConditions.visibilityOfElementLocated(this.productName)).getText(); } public String getProductPrice() { return this.wait.until(ExpectedConditions.visibilityOfElementLocated(this.productPrice)).getText(); } public void addProductToCart() { this.wait.until(ExpectedConditions.visibilityOfElementLocated(this.addToCartButton)).click(); } public String getConfirmationMessage() { return this.wait.until(ExpectedConditions.visibilityOfElementLocated(this.cartConfirmationMessage)).getText(); }
def get_product_name(self): product_name_text = self.wait.until(EC.visibility_of_element_located(self._product_name)).text return product_name_text def get_product_price(self): product_price_text = self.wait.until(EC.visibility_of_element_located(self._product_price)).text return product_price_text def add_product_to_cart(self): self.wait.until(EC.visibility_of_element_located(self._add_to_cart_button)).click() return self def get_confirmation_message(self): cart_confirmation_message_text = self.wait.until(EC.visibility_of_element_located(self._cart_confirmation_message)).text return cart_confirmation_message_text
public async getProductName(): Promise { await browser.wait(ExpectedConditions.visibilityOf(element(this.productName)), browser.allScriptsTimeout, this.productName.toString()); return await element(this.productName).getText(); } public async getProductPrice(): Promise { await browser.wait(ExpectedConditions.visibilityOf(element(this.productPrice)), browser.allScriptsTimeout, this.productPrice.toString()); return await element(this.productPrice).getText(); } public async addProductToCart(): Promise { await browser.wait(ExpectedConditions.visibilityOf(element(this.addToCartButton)), browser.allScriptsTimeout, this.addToCartButton.toString()); await element(this.addToCartButton).click(); return this; } public async getConfirmationMessage(): Promise { await browser.wait(ExpectedConditions.visibilityOf(element(this.cartConfirmationMessage)), browser.allScriptsTimeout, this.cartConfirmationMessage.toString()); return await element(this.cartConfirmationMessage).getText(); }
现在,您已准备好自动化测试用例。
要创建新的测试文件,请右键单击项目中的tests
文件夹,然后从上下文菜单中选择新建 > 测试文件。Sencha WebTestIt 会为您生成一个新类,并等待您为其命名。使用 TypeScript 时,将文件命名为Test1.ts
,使用 Java 时,将文件命名为Test1.java
。这次,您不为 Python 使用蛇形命名法。您使用驼峰命名法,并将测试文件命名为test1.py
。
注意
实际的测试文件应编排针对您的网站或应用程序执行的操作。最好将操作本身留在页面对象中,以确保良好的测试可维护性。
每个测试用例中最重要的部分是块末尾的断言。您可以使用它来验证网站或应用程序的行为是否与您的预期行为匹配,因此可以定义测试是失败还是通过。对于元素的断言,有各种可用的断言框架。
Sencha WebTestIt 根据您选择的脚本语言为您的项目捆绑了一个断言框架。如果您选择使用 Java 编写测试,则会提供 TestNG 框架。如果您使用 TypeScript,则 Protractor 与Jasmine一起是默认设置。对于 Python 用户,提供了 unittest 环境。但是,您可以切换各个组件。
根据使用的自动化框架和语言,您可以创建上表中描述的三个测试用例。
@Test public void SearchForItemTestCase() { // 1. 安排 // 右键单击并 // 选择底部的“实例化页面对象”来创建一个新的页面对象实例 HeaderPo header = new HeaderPo(driver); DetailPagePo detail = new DetailPagePo(driver); header.open("https://demoshop.webtestit.com"); // 2. 操作 // 从初始化的页面对象调用现有操作 header.insertSearchText("Super"); // 3. 断言 // 使用 TestNG 断言来验证结果。 // 例如: // Assert.assertEquals(title, "Test Automation for GUI Testing | Sencha"); Assert.assertEquals(detail.getProductName(), "Super Cool Goo"); Assert.assertEquals(detail.getProductPrice(), "€1,500.00"); } @Test public void AddItemToCartTestCase() { HeaderPo header = new HeaderPo(driver); DetailPagePo detail = new DetailPagePo(driver); detail.open("https://demoshop.webtestit.com/product/super-cool-goo/"); detail.addProductToCart(); Assert.assertTrue(detail.getConfirmationMessage().contains("“Super Cool Goo” has been added to your cart")); Assert.assertEquals(header.getCartCount(), "1 item"); Assert.assertEquals(header.getCartAmount(), "€1,500.00"); }
def test_search_for_item(self): driver = self.get_driver() """ 1. 安排 通过右键单击代码编辑器并选择上下文菜单底部的“实例化页面对象”来创建一个新的页面对象实例 """ header = header_po(driver) detail = detail_page_po(driver) header.open("https://demoshop.webtestit.com") """ 2. 操作 从页面对象实例调用现有操作 """ header.insert_search_text("Super") """ 3. 断言 使用 unittest 断言来验证结果。例如: self.assertEqual(title, "Test Automation for GUI Testing | Sencha") """ self.assertEqual(detail.get_product_name(), "Super Cool Goo") self.assertEqual(detail.get_product_price(), "€1,500.00") def test_add_item_to_cart(self): driver = self.get_driver() header = header_po(driver) detail = detail_page_po(driver) detail.open("https://demoshop.webtestit.com/product/super-cool-goo/") detail.add_product_to_cart() self.assertTrue(detail.get_confirmation_message in "“Super Cool Goo” has been added to your cart") self.assertEqual(header.get_cart_count(), "1 item") self.assertEqual(header.get_cart_ammount(), "€1,500.00")
public async getProductName(): Promise { await browser.wait(ExpectedConditions.visibilityOf(element(this.productName)), browser.allScriptsTimeout, this.productName.toString()); return await element(this.productName).getText(); } public async getProductPrice(): Promise { await browser.wait(ExpectedConditions.visibilityOf(element(this.productPrice)), browser.allScriptsTimeout, this.productPrice.toString()); return await element(this.productPrice).getText(); } public async addProductToCart(): Promise { await browser.wait(ExpectedConditions.visibilityOf(element(this.addToCartButton)), browser.allScriptsTimeout, this.addToCartButton.toString()); await element(this.addToCartButton).click(); return this; } public async getConfirmationMessage(): Promise { await browser.wait(ExpectedConditions.visibilityOf(element(this.cartConfirmationMessage)), browser.allScriptsTimeout, this.cartConfirmationMessage.toString()); return await element(this.cartConfirmationMessage).getText(); }
您已准备好自动化测试用例。
最后,是时候验证我们的实验是否有效了。为此,您必须首先创建一个端点。端点是一组有关测试运行时环境的配置。它定义要使用哪个浏览器或哪个操作系统,以及更多内容。
注意
由于 Selenium WebDriver 的JsonWireProtocol,运行时环境实际上可以位于世界任何地方,因为自动化命令通过 HTTP 发送。
我们将创建一个本地 Chrome 端点并在其上执行我们的测试。
找到执行选项卡
单击+按钮
在端点对话框中输入以下信息
单击保存端点
您可以在本指南的第 4 章中了解有关端点的更多信息。
如果您按照本教程中的所有步骤进行操作,则您的测试用例应在没有错误的情况下执行。Sencha WebTestIt 在您的项目中创建了一个名为reports
的新文件夹。单击其中的 XML 文件将打开报告选项卡,显示您的运行结果。
您还了解了
我们创建了一些建议供您阅读