自动化Test使用详细解析(四) —— 单元测试和UI Test(一)

版本记录

版本号 时间
V1.0 2020.06.23 星期二

前言

自动化Test可以通过编写代码、或者是记录开发者的操作过程并代码化,来实现自动化测试等功能。接下来几篇我们就说一下该技术的使用。感兴趣的可以看下面几篇。
1. 自动化Test使用详细解析(一) —— 基本使用(一)
2. 自动化Test使用详细解析(二) —— 单元测试和UI Test使用简单示例(一)
3. 自动化Test使用详细解析(三) —— 单元测试和UI Test使用简单示例(二)

开始

首先看下主要内容:

在本教程中,您将学习如何使用Xcode测试计划来组织单元测试和UI测试,以及如何测试多种语言/地区的iOS应用。内容来自翻译。

下面就是写作环境

Swift 5, iOS 13, Xcode 11

下面就是正文了。

如今,编写自动化测试已成为开发过程中不可或缺的一部分。它与编程本身一样重要,并且可能很耗时。适当的测试可以丰富技术文档,并防止随着应用程序的发展而出现将来的错误。幸运的是,Xcode提供了完整测试所需的所有工具,并且Xcode测试计划使这些工具更易于使用。

有时候,要在多种条件下测试您所有应用的功能都是很棘手的。您想要涵盖的组合越多,您需要创建的测试方案甚至单独的测试targets就越多。这是新的Xcode测试计划派上用场的地方。

在本教程中,您将测试计划添加到简单的预算应用中。在此过程中,您将学到:

  • 如何创建Xcode测试计划。
  • 为什么要在一个应用程序中创建多个测试计划。
  • 如何在多个地区测试。
  • 如何在测试计划中使用代码诊断和内存管理配置。

是时候使用Xcode测试计划了!

您要处理的项目是使用SwiftUI编写的预算应用程序。

打开入门项目,然后构建并运行。

如您所见,您可以通过点击右上角的加号按钮来创建多个帐户。 您可以通过注册费用和利润来管理余额。


Testing the Tests

现在,返回项目并查看测试类AccountsViewModelUnitTestAccountsViewUITest

AccountsViewModelUnitTest验证AccountsViewModel可以添加和删除帐户以及正确管理余额。 AccountsViewUITest从用户角度验证了一些简单的方案。

通过按Command-U运行测试。 打开Test navigator以查看测试结果:

注意:如果某些UI测试失败,请禁用“连接硬件键盘”选项。

为此,请在模拟器应用程序中选择“ I / O”菜单选项,然后转到Keyboard并取消选中Connect hardware keyboard。 连接硬件键盘后,UI测试似乎无法访问模拟器中的text field

所有测试均为绿色,您可以继续进行!


Unit Tests and UI Tests

单元测试(Unit tests)检查是否每个代码单元(例如类或函数)均产生预期的结果。 单元测试是独立运行的,不依赖于其他模块或组件。 因此,它们消耗很少的时间或资源。 您应该毫不犹豫地编写更多的单元测试!

端到端测试(End-to-end tests)从启动到结束都将验证您的应用程序。可以用于端到端测试的工具之一是UI test,它可以完全复制用户与应用程序进行交互的方式。 UI testunit test慢得多,运行起来也更昂贵。

当您可以用几个单元测试覆盖场景时,应尽量避免编写UI测试。UI测试值得广泛使用来涵盖核心功能。

从上面的测试报告中可以看到,每次运行测试时,都会同时运行UI和单元测试。这在开发过程的早期很方便。但是,随着应用程序变得复杂时,您将希望在不同的时间点或多或少地运行不同类型的测试。

例如,您可能考虑在将功能分支合并到开发分支之前,每次执行单元测试并运行端到端测试。

这就是Xcode测试计划出现的地方!


Creating Your First Test Plans

通过测试计划,您可以控制在特定时间运行哪些测试。在本部分中,您将创建两个测试计划:一个用于单元测试,另一个用于单元和UI测试。

1. Creating a Unit Test Plan

您的第一个测试计划将仅运行单元测试。请按照以下步骤创建和配置您的测试计划:

  • 1) 单击当前scheme名称,BudgetKeeper,然后选择Edit scheme…
  • 2) 在Test部分中,单击Convert to use Test Plans…
  • 3) 在出现的弹出窗口中,选择Create empty test plan,然后单击Convert…
  • 4) 将其命名为UnitTests.xctestplan,然后单击Save。 通过在方案编辑器弹出窗口中单击Close来关闭方案编辑器(scheme editor)。 请参阅下面的注释。
  • 5) 您现在在项目的根目录中有一个UnitTests.xctestplan文件。 选择它,然后使用底部附近的小+图标单击Add Test Target
  • 6) 选择BudgetKeeperTests,然后单击Add

注意:在上述第4步中保存UnitTests.xctestplan时,Xcode可能会建议BudgetKeeper.xcodeproj文件内的默认保存位置—然后在尝试保存时失败。 为防止此失败,请确保将UnitTests.xctestplan保存在项目文件夹的根目录中,而不是在BudgetKeeper.xcodeproj内部。

现在,按Command-U运行测试并查看Test navigator

您会看到,在新的测试计划中,只有单元测试正在执行。 很好!

现在,您需要一个计划来运行所有测试。

2. Creating a Full Test Plan

重复上述步骤,创建另一个测试计划。 将计划命名为FullTests.xctestplan。 选择BudgetKeeperTestsBudgetKeeperUITests作为测试targets。 如果正确执行此操作,则会在当前scheme中看到两个计划:

现在,将FullTests.xctestplan设置为您的默认计划,因为在下一部分中您将进一步了解UI测试。

注意:您可以通过Option单击Xcode中的scheme名称来更快地访问方案编辑器(scheme editor)


Testing Multiple Localizations

项目中包含几个本地化文件:

事实证明,您的应用程序已支持两种语言-英语和德语。

1. Setting up Configurations

如果您的应用取决于用户所在的地区或语言,则可以针对几种语言和地区运行UI测试。 您的budget应用程序及其使用的货币符号就是一个很好的例子。

通过创建两个单独的配置,设置FullTests计划以执行英语和德语的UI测试:

  • 1) 选择FullTests.xctestplan。 在Configurations选项卡中,通过按Enter并替换现有文本,将Configuration 1重命名为German
  • 2) 在配置设置中,将Application Language设置为German。 将Application Region设置为Germany
  • 3) 仍在Configurations选项卡中,单击+添加新配置。
  • 4) 选择新创建的配置文件,然后按Enter将其重命名为English
  • 5) 在English配置中,将Application Language设置为English。 将Application Region设置为United States

2. Running the Localization Tests

转到AccountsViewUITest并选择Run in All Configurations。 通过右键单击AccountsViewUITest左侧的Play按钮来执行此操作:

然后,在同一菜单中,选择Jump to Report以查看测试报告:

哦,不,它失败了! 您如何解决?

首先查看testUpdateBalance()。 展开该测试的German配置的报告,以找到失败的原因:

单击Automatic Screenshot文本附近的Eye图标:

显然,您在指定的地区使用了错误的货币符号:Germany。 货币以美元显示,但应该是欧元!

3. Adapting the Code for Locale-Dependent Tests

转到AccountView.swift解决此问题。 您将在此处找到计算出的属性balanceString

private var balanceString: String {
  let amount = AmountFormatter.string(from: abs(account.balance)) ?? ""
  let balance = "$" + amount
  return account.balance < 0 ? "-" + balance : balance
}

美元符号是hard-coded的! 如您所知,硬编码很少是解决方案,这也不例外。

更新您的代码:

private var balanceString: String {
  // 3
  let amount = AmountFormatter.string(from: abs(account.balance)) ?? ""
  let balance = currencySymbol + amount
  return account.balance < 0 ? "-" + balance : balance
}

// 1
private var currencySymbol: String {
  // 2
  return Locale.current.currencySymbol ?? ""
}

这是您在这段代码中所做的:

  • 1) 您声明一个新的计算属性currencySymbol
  • 2) 您可以从当前用户区域设置中获取货币符号。 这样,货币符号对于德国将是,对于美国将是$
  • 3) 最后,您在balanceString中使用新声明的属性,而不是硬编码的值。

再次运行UI测试并打开测试报告:

哦! testAddAccount()仍然失败!

显然,导航标题的翻译出了点问题。 查看Localizable.strings (German),您会看到标题为New Account的翻译:

"BudgetKeeper" = "BudgetKeeper";
"New Account" = "Neues Konto";
"Update Balance" = "Kontostand updaten";
"OK" = "OK";
"Save" = "Speichern";
"Enter the name" = "Gib den Namen ein";

那还有什么错呢? 转到CreateAccountView.swift进行调查。

确定,您可以通过调用navigationBarTitle(_ :)来设置导航标题。 到目前为止,一切都很好。

但是key是错的! 它应该是New Account,而不是New accountAccount具有大写字母A,而不是小写字母a。 解决方法如下:

.navigationBarTitle("New Account")

再次运行测试以验证正确的本地化:


Analyzing an App Alongside Testing

Xcode提供了多种工具来分析您的应用程序的运行情况,但其中许多工具无法一起使用或会影响性能。 您还必须记住该工具存在,并打开(和关闭)它们,并注意结果。 好消息! 您可以将分析工具设置为测试计划的一部分! 转到FullTests计划的配置之一。 看一下底部的设置:

1. Sanitizers

这三个sanitizers将在您的应用程序运行时检查以下内容:

  • Address Sanitizer (ASan)检测到代码中的内存使用错误。 启用ASan可能会稍微降低测试速度并增加内存使用量,但是确保您的代码没有内存冲突是值得的。
  • Thread sanitizer(TSan)可帮助您检测data races,其中多个线程以不安全的方式访问和修改内存区域。 这些都是很难预测的,因此很难找到和调试。
  • Undefined Behavior Sanitizer(UBSan)检测到诸如除以零或访问其边界之外的数组之类的问题。

注意:您不能在同一配置中打开Address sanitizerThread sanitizer。 在这种情况下,一种合适的解决方案是在German配置一个sanitizer,在English配置另一个sanitizer

2. Runtime API Checking

默认情况下,Main Thread Checker 处于启用状态,并且在测试时应保持这种方式。 如果在后台线程上使用UIKitAppKit之类的框架,它将发出警告。 您应该只在主线程中更新UI。

3. Memory Management

Malloc Scribble, Malloc Guard Edges and Guard Malloc帮助您检测释放的内存的使用情况和缓冲区溢出(buffer overruns)。 后者意味着您的程序在将数据写入缓冲区时会超出缓冲区的范围。 这导致覆盖邻近缓冲存储器位置的存储。

注意:不能同时使用这些工具,也不能在同一配置中同时使用ASanTSan

启用Zombie Objects设置后,程序中的对象达到保留计数0时将不会被释放。相反,它们将像僵尸一样半活半死。 当程序尝试访问此类对象时,您会收到警告。

做得好! 您现在已经了解了如何组织测试以及如何在多个本地化环境中进行测试。 这意味着没有更多的理由不编写这些测试!

另外,要了解有关Xcode中的内存管理工具的更多信息,请查看Apple的Malloc Debugging文档。

后记

本篇主要讲述了单元测试和UI Test,感兴趣的给个赞或者关注~~~

你可能感兴趣的:(自动化Test使用详细解析(四) —— 单元测试和UI Test(一))