许多质量保证工程师的工作涉及开发测试用例并验证以下应用程序。应用程序越大,测试用例越多,回归测试所需的时间就越多。但是,如果我们至少可以将回归测试的一部分委托给机器怎么办?
这是通过UI测试进行应用程序测试进行救援的地方。
这些测试模拟用户交互并允许自动验证应用程序的各种状态。
UI测试可用于验证屏幕之间的导航,是否显示特定元素,所需的文本是否出现在按钮上,等等。
在本文中,我将解释并提供如何开始编写简单的Swift测试以自动进行iOS应用程序的测试的示例。
要编写测试,您将需要SWIFT的基本知识(包括基本语法和对对象的编程的理解)和Mac计算机,因为测试环境和模拟器仅在MACOS上可用。
做好准备!
要编写测试,我们需要安装Xcode应用程序。
你们大多数人可能已经安装了它并且熟悉它,但是如果不是,则是一个简短的指示:
要安装Xcode,建议将MacOS更新为最新版本。 Xcode的最新版本通常与MacOS的最新主要版本兼容。
安装Xcode的主要方法有两种:
- 从Mac App Store下载是最简单的方法,但它可以使更新Xcode更加复杂且耗时。如果需要,维护两个版本的Xcode也可能更具挑战性。
- 从developer.apple.com下载是大多数开发人员首选的方法,因为它提供了更大的灵活性。 访问https://developer.apple.com/download/all/并下载最新的稳定版本的Xcode。确保选择稳定版本,而不是beta或发布候选版本。下载完成后,解开已下载的文件并将Xcode应用程序移至应用程序文件夹。
安装后,打开Xcode。在第一次启动时,将提示您安装其他组件。同意安装它们。
安装其他组件后,将打开一个项目选择窗口。这表明Xcode已准备就绪。
实验室鼠标应用程序
对于您的第一次测试写作经验,最好使用自己的简单应用。例如,您可以在学习基本的迅速技能或在宠物项目上工作后创建一个简单的应用程序。
在本文中,我将以自己的宠物项目为例。这是一个非常简单的应用程序,旨在供培训师管理其客户数据库。
在此应用程序中,您可以:
- 创建新客户
- 将资金添加到客户的余额
- 从客户的余额中扣除培训课程的钱
- 查看培训日志
- 关于客户的记录
该应用程序具有以下外观
在本文中,我们不会涵盖余额充值,扣除和查看交易历史记录的其他屏幕。
第一个测试的测试用例:
我们要测试的流是创建新客户端的。最初,我们将专注于积极的情况。我们想检查以下方面:
- 客户创建屏幕打开。
- 在屏幕上,您可以输入客户的名字,姓氏,电话号码,培训费用,选择定价选项并填写注释。
- 单击“完成”按钮后,客户端创建屏幕应关闭,并且具有输入名称和姓氏的新单元格应显示在客户端列表中。
测试用例在实际测试之前写入时总是更好,因此在测试实施过程中,我们可以专注于编写代码。如果我们在制定测试时编写测试用例,则可能会遭受测试案例的质量,我们可能会忽略重要的细节。
在Xcode中为UI测试创建目标
要启用编写UI测试,您需要将UI测试的目标添加到现有项目中。按照以下步骤:
打开Xcode和您的项目。
在顶部菜单中,单击“文件” - >“ new” - >“目标”。
在出现的窗口中,从可用选项中选择“ UI Testing Bundle”。
在目标名称窗口中,将所有内容保持原样,然后单击“完成”。
之后,我的项目中出现了一个名为“ fizrookuitests”的文件夹,其中包含两个文件:“ fizrookuitests”和“ fizrookuitestslaunchtests”
现在已经设置了我们的UI测试目标。
现在让我们继续讨论xctest。
找出xctest
让我们导航到“ fizrookuitests”文件。在此文件中,我们有一个预先编写的测试模板:
让我们逐步了解包括的内容:
- 导入xctest是测试框架的导入语句。我们需要在每个测试文件中导入此导入,因为我们将在所有测试中使用XCtest类。
- 类fizrookuitests:xctestcase –此行表示XCtestCase类的类继承。运行测试时,XCtest搜索从Xctestcase继承的所有类并执行其中的测试。我们编写的每个测试都应从xctestcase继承。
- func testexample()抛出 - 这是代表其中一个测试的函数的声明。运行测试时,XCtest寻找以“测试”开头的所有方法,并将每种方法作为单独的测试执行。
- func testLaunchPerformance()抛出 - 这是一项书面测试,可衡量应用程序的启动速度。我们不需要我们的基本测试测试,因此应将其删除。
- 我们现在不会深入研究其余部分,因为它们需要深入研究Xctest。
可以执行此文件的测试。尽管它们没有验证任何内容,但我们可以运行它们并查看模拟器启动,以及在控制台中显示的测试执行数据。
要运行测试,请单击位于“ Fizrookuitests”左侧的菱形图标。
单击“测试运行”按钮后,模拟器将打开,并且将执行唯一的测试“ Testexample”。通过的测试将以绿色的符号标记,有关传递测试的信息将显示在控制台中。
。现在我们可以继续编写自己的测试。
编写第一个测试
在我们的第一个测试中,我们将通过客户端创建流。我们将根据我们之前编写的测试案例进行此操作。
为了简化编写测试的过程,Xcode提供了一个名为“测试记录器”的功能,该功能使您可以在模拟器中记录操作并将其转换为代码。
要使用它,请将光标放在测试方法中,然后单击记录按钮。
让我们开始编写一种新方法,该方法将包含与测试新客户的创建相关的所有逻辑:
func testCreateNewCustomer() throws {
}
现在将光标放入此方法中,然后单击红色记录图标。
单击按钮后,模拟器将打开,在其中,我们执行的操作以创建客户端:
在XCode执行操作期间,将记录这些操作的代码,从而导致以下代码:
let app = XCUIApplication()
app.navigationBars["Clients"].buttons["Add"].tap()
let tablesQuery = app.tables
let firstNameTextField = tablesQuery.textFields["First name"]
firstNameTextField.tap()
let lastNameTextField = tablesQuery.textFields["Last name"]
lastNameTextField.tap()
let phoneTextField = tablesQuery.textFields["Phone"]
phoneTextField.tap()
let trainingPriceTextField = tablesQuery.textFields["Training Price"]
trainingPriceTextField.tap()
app.tables.staticTexts["Choose"].tap()
app.collectionViews.buttons["Per session"].tap()
let textView = tablesQuery.cells.containing(.staticText, identifier:"Notes").children(matching: .textView).element
textView.tap()
app.navigationBars["New Client"].buttons["Done"].tap()
在这里,我们可以看到如何逐步执行以下操作:
- 我们找到了导航栏,然后单击“添加”按钮。
- 我们找到了带有标签“名字”,“姓氏”,“电话”和“培训价格”的文本字段,并在上面敲击。
- 我们单击了“选择”按钮,然后选择了“每个会话”选项。
- 我们在标有“笔记”的单元格中找到了文本视图。
- 再次找到导航栏并单击“完成”按钮。
除了键盘输入外,还记录了模拟器中的大多数操作。对于录制文本输入,有两个选项:
- 使用模拟器的键盘输入数据。
- 在代码中以编程方式输入数据。
我们现在将应用第二个选项。对于输入数据,每个文本字段都有一个称为typeText
的方法。
让我们使用以下方式使用typeText
方法添加代码:
func testCreateNewCustomer() throws {
let app = XCUIApplication()
app.navigationBars["Clients"].buttons["Add"].tap()
let tablesQuery = app.tables
let firstNameTextField = tablesQuery.textFields["First name"]
firstNameTextField.tap()
firstNameTextField.typeText("John")
let lastNameTextField = tablesQuery.textFields["Last name"]
lastNameTextField.tap()
firstNameTextField.typeText("Apple")
let phoneTextField = tablesQuery.textFields["Phone"]
phoneTextField.tap()
phoneTextField.typeText("+352911678442")
let trainingPriceTextField = tablesQuery.textFields["Training Price"]
trainingPriceTextField.tap()
trainingPriceTextField.typeText("100")
app.tables.staticTexts["Choose"].tap()
app.collectionViews.buttons["Per session"].tap()
let textView = tablesQuery.cells.containing(.staticText, identifier:"Notes").children(matching: .textView).element
textView.tap()
textView.typeText("Powerful")
app.navigationBars["New Client"].buttons["Done"].tap()
}
现在,让我们将以下行添加到测试的开头,在let app = XCUIApplication()
行之后:
app.launch()
这是在测试开始时启动应用程序的必要条件。现在,您可以运行测试并查看模拟器中将执行的内容。单击我们测试旁边的菱形图标,然后查看模拟器:
我们可以看到我们的代码如何执行整个必需操作,包括文本输入!这很棒。
现在,让我们回想一下我们的最初任务:我们需要验证客户端是实际创建和显示在客户端列表中的。我们的测试已经通过了整个流程,现在我们只需要添加一张列表中客户端的检查。
测试记录器无法帮助我们检查列表中客户的存在,因此我们需要自己编写测试。
由于我们将根据其名称和姓氏在客户端列表中搜索创建的客户端,因此让我们首先将名称和姓氏提取到单独的变量中,以便我们可以在进一步的检查中使用它们。让我们修改现有代码如下:
app.navigationBars["Clients"].buttons["Add"].tap()
let firstName = "John"
let lastName = "Apple"
let tablesQuery = app.tables
let firstNameTextField = tablesQuery.textFields["First name"]
firstNameTextField.tap()
firstNameTextField.typeText(firstName)
let lastNameTextField = tablesQuery.textFields["Last name"]
lastNameTextField.tap()
lastNameTextField.typeText(lastName)
现在,创建客户端时,将输入变量“ firstName”和“ lastname”的数据。
让我们继续检查列表中客户的存在。将以下代码添加到测试末尾:
let nameOfNewCustomer = firstName + " " + lastName
let isNewCustomerExists = tablesQuery.staticTexts[nameOfNewCustomer].exists
XCTAssertTrue(isNewCustomerExists)
我们在这里做什么:
- 我们创建了一个用客户端的最终名称的变量,即“约翰·苹果”。
- 我们在屏幕上使用客户端名称的静态文本检索元素的存在并将其存储在变量中。
- 我们使用xctest断言来检查代表元素存在的变量是否为真。如果变量是错误的,则测试将失败。
现在我们可以运行测试并查看会发生什么。
我们的测试正在通过,并且正在执行新客户的存在检查。
出于验证目的,我们可以尝试通过删除名称ofnewcustomer变量中的名称和姓氏之间的空间来打破测试,并验证在这种情况下测试将失败。
这样,我们已经写了一项测试,该测试完全通过客户创建流量,并在创建后验证客户列表中的客户存在。
那呢?
- 使用可访问性标识符 - 在我们的测试中,我们目前正在使用基于文本的元素引用。这意味着如果语言或任何文本改变,我们的测试将破坏。为了防止这种情况,我们应该使用可访问性标识符。您可以在这里了解更多有关它们的信息:https://ayaakl.wordpress.com/2020/04/19/making-your-ios-app-accessible-for-ui-tests-ayas-cookbook-about-ios-accessibility-identifiers/
- 管理不同的UI元素,例如Uislider,TableView和其他https://www.hackingwithswift.com/articles/148/xcode-ui-testing-cheat-sheet
- 使用不同的方法在应用程序中找到所需的UI元素至关重要。测试记录器可能并不总是找到访问元素的最佳方法,因此学习和利用替代方法有效地定位接口元素很重要。 https://www.browserstack.com/guide/xcuitest-locators-to-find-elements
- 在应用程序中使用异步事件(例如网络请求)至关重要。我们的大多数应用程序都使用网络请求,并且测试需要能够等待其响应。您可以在此处找到有关此主题的更多信息:https://medium.com/quality-engineering-university/xcuitests-why-how-to-apply-wait-for-element-e42ef300ca93
自动测试是测试人员增长的绝佳机会。通过适当的奉献精神,它可以更轻松地测试简单和例行的方案,从而腾出大量时间来完成更重要和有趣的任务。