使用KIF 进行 iOS UI 测试

用户期待iOS应用的高水准用户体验,因而你需要设计、开发和测试你的应用来满足这一不断上升的期望。为了达成这个目标,你会投入多少时间进行原始人工的用户界面测试?你知道这活儿怎么干…从Xcode启动你的应用,并不断的用手指点击同一些按钮来确保你的设计中没有退步。相比这些,你当然更愿意做其它一些事情?

《使用KIF 进行 iOS UI 测试》

考虑下使用Xcode 5中增强的UI测试,还有 OS X Server中支持的持续集成 这篇文章展示了苹果公司为开发者贡献的最好的工具。

你也许会说,这很棒,但是如何让那些简单的用户动作测试变得自动化呢,例如确保一个在合适区域的双击或触摸后会进入正确的视图?即使是测试脚本和机器人也不会有能在屏幕上滑动的电容式触摸手指…呃…它们有手指么?

在这篇教程中,你将会学习到一些有关 KIF 的东西(Keep it Functional), 它是一个开源的用户界面测试框架. 使用 KIF, 并利用 iOS中的辅助功能 API, 你将能够编写模拟用户输入(例如点击、触摸和文本输入)的测试。

它提供自动化的、真实的用户界面操作, 帮助放松你的心情,因而你就可以只去关注自己的杀手级应用了,而不是在UI测试上耗费你职业生涯的一半时间。

让我们开始测试工作吧!

入门

我们以一个叫做茄薯Solanum(一个马铃薯品种的名字)的计时器应用为例。这是一个基于番茄工作法的应用。

它是这么运作的:

  • 按照设定好的时间工作,接着休息一下,然后重复工作和休息.
  • 经过这样若干个循环之后, 你就会休息一段更长的时间.

这个应用就是一个能够持续跟踪时间区段的简单计时器。

这款应用之后能使你的开发工作变得更加高效!

《使用KIF 进行 iOS UI 测试》

从 这里 下载并解压缩入门项目.注意 KIF 是一个独立的项目,它是为茄薯应用构建一个用于测试目标的库。因此你需要双击 solanum.xcworkspace 以便在Xcode中打开项目,而不是 solanum.xcodeproj。在项目导航视窗中找到这两个项目,如下图所示:

《使用KIF 进行 iOS UI 测试》

将应用的目标设置到solanum,然后选择3.5或者4英寸的iPhone模拟器目标。不要使用64位,因为KIF在64位模拟器上有一些问题。构建并运行这个应用。四处瞧瞧,了解一下,然后切换到Settings。

《使用KIF 进行 iOS UI 测试》

应用有一个能够加速时间流逝的调试模式。因此你可以设置一个20分钟的计时器,测试时花10秒完成这个过程。这只是为了帮助你测试应用,你应该不会想花20分钟等着看它运行吧。

开启调试模式来加速计时器,接着点击Clear History按钮,然后在确认弹出视图上点击Clear。这几步确保了你是在一个干净的环境中开始测试作业。返回到Xcode并把应用停下来.

测试前操作

在项目浏览器中,展开solanum项目。 右击UI测试文件夹并点击New File…来加入你的新测试用例。

《使用KIF 进行 iOS UI 测试》

选择 iOS\Cocoa Touch\Objective-C class 并点击 Next, 将类命名为 UITests 并使其成为 KIFTestCase 的子类。

《使用KIF 进行 iOS UI 测试》

点击Next并确保文件已经被添加到UI Tests目标中, 而不是 solanum 目标。 然后点击接下来Create保存文件.

KIFTestCase是SenTestCase的一个子类. 那意味着你拥有了大部分的标准 OCUnit 测试方法和机制可以使用,如果你已经很熟悉单元测试的话。

打开UITests.m,并在@implementation 一行添加如下的方法:

- (void)beforeAll {
  [tester tapViewWithAccessibilityLabel:@"Settings"];

  [tester setOn:YES forSwitchWithAccessibilityLabel:@"Debug Mode"];

  [tester tapViewWithAccessibilityLabel:@"Clear History"];
  [tester tapViewWithAccessibilityLabel:@"Clear"];
}

beforeAll 是一个在所有测试运行之前被调用一次的特殊方法。你可以为你这里运行的测试设置任何实体变量和初始化条件.

tester 对象是指定的KIFUITestActor 类的一个缩略名称。这个类包含了模拟用户动作的方法,包括触摸和滑动.

tapViewWithAccessibilityLabel 这也许是最常被用到的测试动作方法。正如其名称所显示的,它可以在给定的辅助标签模拟在视图上的触击。在大多数情况下,辅助标签和可视的文本标签(例如按钮组件)是配套的。否则你就需要手动设置辅助标签.

一些控件,诸如 UISwitch,更加复杂,需要比简单的触击更复杂的步骤来触发。 KIF 提供了一个特殊的 setOn:forSwitchWithAccessibilityLabel: 方法来改变一个切换的状态.

总之,这个方法对测试动作进行了四步操作:

  • 触击“Settings” 选项卡按钮条.
  • 将 “调试模式Debug Mode” 切换到它的“开启”状态.
  • 触击 “Clear History” 按钮.
  • 在UIAlertView上触击“Clear”按钮.

这步看起来很眼熟? 应该是熟悉的! 它们就是之前章节中你手动进行的操作!

点击Product Test菜单或者使用Command-U运行测试。应用开始运行,然后KIF接手,自动开启调试模式并清除历史记录.

如果你启用了通知,Xcode将告知你测试的状态:

《使用KIF 进行 iOS UI 测试》

有时候测试运行器或者说KIF可能会有一点挑剔,拒绝运行测试,你只能看到一个空白的模拟器屏幕。如果遇到这样的情况,那么:

  • 清理一下项目(Product\Clean)
  • 构建并运行
  • 等待应用启动
  • 在Xcode中终止应用的运行

这一过程确保了模拟器正在运行,并且你正在最新的构建上进行操作。经过上面的几步之后,试试再一次运行测试。问题应该会消失

如果问题依然存在, 你可以参考 KIF 故障排除步骤

现在你已经在 beforeAll 中有了一个测试前置动作, 是时候加入你的第一个测试了!

一个简单的测试:随处点击

该应用程序有一个标准的选项卡界面,三个选项卡中,每一个都使用了UINavigationController。先做个热身吧,测试一下:

  • 故事版被适当地连接起来
  • 选项卡展示正确的视图

选项栏按钮自动地设置成类似文本标签这样的辅助标签,所以KIF可以通过设置选项栏中的“历史”、“定时器”、“设置”标签找到历史、计时器和设置。

历史选项卡有一个显示所有定时器执行任务的表视图。从solanum组里打开HistoryViewController.m,在viewDidLoad末尾处添加以下几行:

[self.tableView setAccessibilityLabel:@"History List"];
[self.tableView setIsAccessibilityElement:YES];

这样,表视图的辅助标签就设置好了,KIF能够找到它。通常情况下,一个表视图仅在空的情况下才能被访问。表视图的单元格有可能被当做是一个目 标,所以表视图它本身会被藏在辅助功能的API之下。基本上,辅助功能的API在默认情况下假定表视图是不重要的。就辅助本身而言,这是合理的。不过如果你可能想在KIF中引用表视图,那么可以使用setIsAccessibilityElement:,它确保表视图始终是可访问的,不管其是否有内容。

对于使用辅助功能的用户来说,非空的表格视图可以访问会使操作复杂化。在你的应用中,你可以把相应的代码包裹在#ifdef DEBUG#endif指令之间,这样这些代码就只会被编译到调试构建中。DEBUG预处理器宏已经在Xcode项目模板中被提前定义好了。

Timer 选项卡有一些控件,而“任务名称”文本框放在了视图的顶部,以方便用户使用。你无需通过代码来设定标签,只需可以打开 Main.storyboard 并找到Timer View Controller视图. 选择task name text field#。

《使用KIF 进行 iOS UI 测试》

打开Utilities,选择Identity Inspector。提示:从左边数第三个图标, 或者使用快捷键“⌥ ⌘ 3`。

《使用KIF 进行 iOS UI 测试》

在inspector的Accessibility下,Label一栏中输入Task Name。小心,这是大小写敏感的。确保输入了大写的 T 和 N!

《使用KIF 进行 iOS UI 测试》

Settings 面板已经设置好了视图的辅助标签,你可以进行下一步操作了!

在你自己的项目中,你将需要继续填写辅助标签,你可以通过代码,也可以通过上述 Interface Builder的方式。为了方便,示例应用余下来的选项已经设置好了。

回到 UITests.m, 在beforeAll之后加入这个方法:

- (void)test00TabBarButtons {
 // 1
 [tester tapViewWithAccessibilityLabel:@"History"];
 [tester waitForViewWithAccessibilityLabel:@"History List"];

  // 2
 [tester tapViewWithAccessibilityLabel:@"Timer"];
 [tester waitForViewWithAccessibilityLabel:@"Task Name"];

  // 3
[tester tapViewWithAccessibilityLabel:@"Settings"];
 [tester waitForViewWithAccessibilityLabel:@"Debug Mode"];
    }

测试运行器会在运行时寻找所有以test开头的方法, 然后按字母顺序运行它们。这个方法以test00开头,因此它会在你之后加入的方法之前运行,那些是以诸如test10test20这样的名字开头的。

这些方法会进行类似一些动作: 触击标签栏,检查期望的视图是否被显示在屏幕上。waitForViewWithAccessibilityLabel:默认的超时时间是10秒。如果在这段时间内预期的东西没有显示,测试就宣告失败。

点击 Product\Test 或者 Command-U 运行测试。你会注意到beforeAll中的步骤会清除掉历史记录,接着test00TabBarButtons会接管并按顺序切换到历史、定时器和设置标签。

《使用KIF 进行 iOS UI 测试》

哈哈,你看到了吗?你只是编写并运行了一个接口测试, 就会看到你的小应用自己在“启动”了!恭喜了! 你正在掌握自动化UI测试的旅途上。

用户输入

当然,切换标签很棒,不过我们也该关注一下更加真实的动作:输入文本,触发模式对话框,以及选中表视图中的一行。

测试应用中内置了更改工作时间、休息时间、推荐的重复次数的预设功能。如果你很好奇,想查看他们的定义,那么可以浏览一下PresetsViewController.m中的presetItems

每个预设本身就可以成为一个测试。但是作为其他测试的一部分更有效。因此我们把它独立出来成为一个辅助方法。

把以下的方法添加到UITests.m的实现模块中去:

- (void)test00TabBarButtons {
 // 1
 [tester tapViewWithAccessibilityLabel:@"History"];
  [tester waitForViewWithAccessibilityLabel:@"History List"];

 // 2
[tester tapViewWithAccessibilityLabel:@"Timer"];
[tester waitForViewWithAccessibilityLabel:@"Task Name"];

 // 3
 [tester tapViewWithAccessibilityLabel:@"Settings"];
[tester waitForViewWithAccessibilityLabel:@"Debug Mode"];
}

这里的第一步是切换到计时器标签,然后触击导航栏中的预设按钮。当“预设列表”表视图出现的时候,触击指定的一行。

触击行会导致视图控制器会消失,所以要用waitForAbsenceOfViewWithAccessibilityLabel:来保证它在你继续下一步之前已经消失了。

你注意到了吗?这个方法不是以test为开头的。测试运行器是不会自动运行它的。你需要在测试中手动调用这个方法。

现在,添加以下测试方法到UITests.m:

- (void)test10PresetTimer {
  // 1
  [tester tapViewWithAccessibilityLabel:@"Timer"];

  // 2
  [tester enterText:@"Set up a test" intoViewWithAccessibilityLabel:@"Task Name"];
  [tester tapViewWithAccessibilityLabel:@"done"];

  // 3
  [self selectPresetAtIndex:1];

  // 4
  UISlider *slider = (UISlider *)[tester waitForViewWithAccessibilityLabel:@"Work Time Slider"];
  STAssertEqualsWithAccuracy([slider value], 15.0f, 0.1, @"Work time slider was not set!");
}

KIF测试操作有可读性很好的名字,看看你能不能发现接下来会发生什么?把它看成是一个……测试!没错,我故意用了双关语。

好的,这就是实际发生的步骤:

  1. 切换到计时器标签。
  2.  在“任务名”辅助标签的文本框中输入“Set up a test”(记住,你之前添加了这个标签到面板中)。触击“Done”按钮来关闭键盘。
  3. 请求辅助方法来选择第二个预设。
  4. 选择预设会改变滑动器的值,所以要确保它确实更改为正确的值。

在代码最后一部分,你会发现一个有用的技巧:waitForViewWithAccessibilityLabel:。它不仅仅可以等待视图出现,还可以返回一个指针到视图中去。这样,你可以将返回值类型转换成UISlider,以便匹配适当的类型。

由于KIF测试用例也是常规的OCUnit测试用例,因此你可以调用标准的STAssert断言宏。断言是运行时的检查项,如果某些条件不满足,断言会导致测试失败。最简单的断言是STAssertTrue,用来判断传入参数是否为true。

STAssertEquals会检查传入的前两个参数是否相等。滚动条的值是float类型,所以要注意匹配他们的类型。因此,在断言里我们使用15.0f。此外,你还需要注意浮点数的误差,这是因为浮点数的值不可能是100%精确的。比如说,15.0实际上可能被存储为 15.000000000000001。所以STAssertEqualsWithAccuracy是一个更好的选择,它的第三个参数指定偏差范围。在这种情况下,如果该值的误差在-0.1到+0.1之间,断言仍然能通过。

用Command-U运行测试。你会看到这三个序列:beforeAll清除历史记录,test00TabBarButtons在每个标签间切换,最后的是test10PresetTimer,输入一个任务名并选择一个预设。

这是另一个成功的测试用例!此时,你的测试模仿用户的触击,甚至键盘输入,但是还有更多惊喜在后头!

启动定时器

下面给出一个例子,定时循环跑一个应用程序,应用的用户可能选择:工作8分钟,休息2分钟,工作8分钟,休息2分钟,最后工作8分钟。接下来是一个较长的休息。然后再重新启动应用程序。

以上例子的参数是:

  • 工作时间:8分钟
  • 休息时间:2分钟
  • 重复次数:3

接下来的KIF测试需要输入这些参数,然后点击“开始工作”按钮来启动定时器。添加以下的方法到UITests.m,直接加在你之前添加的测试之后:

- (void)test20StartTimerAndWaitForFinish {
  [tester tapViewWithAccessibilityLabel:@"Timer"];

  [tester clearTextFromAndThenEnterText:@"Test the timer"
    intoViewWithAccessibilityLabel:@"Task Name"];
  [tester tapViewWithAccessibilityLabel:@"done"];

  [tester setValue:1 forSliderWithAccessibilityLabel:@"Work Time Slider"];
  [tester setValue:50 forSliderWithAccessibilityLabel:@"Work Time Slider"];
  [tester setValue:1 forSliderWithAccessibilityLabel:@"Work Time Slider"];
  [tester setValue:8 forSliderWithAccessibilityLabel:@"Work Time Slider"];

  [tester setValue:1 forSliderWithAccessibilityLabel:@"Break Time Slider"];
  [tester setValue:25 forSliderWithAccessibilityLabel:@"Break Time Slider"];
  [tester setValue:2 forSliderWithAccessibilityLabel:@"Break Time Slider"];
}

因为这个测试会在test10PresetTimer(这个测试会设置任务名)后立刻运行,你可以使用clearTextFromAndThenEnterText:intoViewWithAccessibilityLabel:,而不是使用enterText:intoViewWithAccessibilityLabel:清除任何现存的文本。

最后,这里有几个setValue:forSliderWithAccessibilityLabel:调用。这是UISlider指定的给新变量赋值的方法。注意,并不总是很精确。KIF实际上是模拟触击事件去设置新的值,有时候像素的计算会有所偏差。不过这没什么大问题,因为我们的手指也不是特别精确!

你仅需要设置每个滚动条的值一次。多次的调用仅仅是为了反复,所以你会看到KIF不停地更改值。

使用Command-U运行测试。

剩下的UI测试是在UIStepper控制器中设置重复的次数,还有“开始工作”按钮。“开始工作”按钮很简单——你可以使用tapViewWithAccessibilityLabel:模拟触击。但对于UIStepper来说,我们需要采用一些迂回策略。

定制触击

如下图所示,UIStepper控制器分为两部分,因此,如果你仅仅调用tapViewWithAccessibilityLabel:,很难确定会发生什么。

《使用KIF 进行 iOS UI 测试》

KIF会开始尝试触击控制器的中心。如果它是一个不可触击的区域,它会接下来尝试点击左上角、右上角、左下角、右下角。结果显示,触击+、-之前的分界线会触发+,所以它会不断地增加重复次数。

但是如果你想减少次数呢?有一些变通的方法的,例如深入子视图找到减号的按钮,另一种方法则是使用KIF的tapScreenAtPoint:测试操作,可以模拟触击屏幕上的任意点。

你对CGGeometry了解得如何?如何计算出+/-按钮在窗口中的坐标?准备好来证明你的实力没?为什么不接受这个挑战呢?这完全是可选的, 你可以直接跳到下面去查看代码和计算。但是,如果想测验一下你的技能,可以尝试在偷看答案之前先自己写一下代码。

请注意,你很快需要将下面的代码添加到测试中,这个任务只是测试你的数学和CGGeometry能力。

UIStepper Geometry

首先,你需要引用UIStepper:

UIStepper *repsStepper = (UIStepper*)[tester waitForViewWithAccessibilityLabel:@"Reps Stepper"];

然后你可以找到中心点:

CGPoint stepperCenter = [repsStepper.window convertPoint:repsStepper.center
fromView:repsStepper.superview];

UIStepper可以是在嵌套视图内,而你真正想要的是UIStepper的中心点相对于整个窗口的坐标,因此需要调用convertPoint:fromView:

现在,你得到了中心点相对于窗口的位置,你可以减少x轴的值来获取到减号的按钮,或者增加x轴来获取加号的按钮。

CGPoint minusButton = stepperCenter;
minusButton.x -= CGRectGetWidth(repsStepper.frame) / 4;

CGPoint plusButton = stepperCenter;
plusButton.x += CGRectGetWidth(repsStepper.frame) / 4;

如果增加或者减少UIStepper宽度的1/4,就会正好到达加号、减号按钮的中间位置。

瞧!这两个点,相当于UIStepper控制器中的加号/减号按钮的中心点。

触击屏幕的指定点是万不得已的方法,但有时它是测试UI的唯一的方法。例如,你也许会有一个自行定制的控制器没有实现UIAccessibility Protocol

定时器收官

好的,你已经到了定时器测试的最后一步了。你开始意识到用KIF做UI测试的潜力了么?很好!

最后的步骤是设置重复次数,然后启动定时器。添加以下代码到UITests.m中的test20StartTimerAndWaitForFinish的结尾:

 // 1
  UIStepper *repsStepper = (UIStepper*)[tester waitForViewWithAccessibilityLabel:@"Reps Stepper"];
  CGPoint stepperCenter = [repsStepper.window convertPoint:repsStepper.center
                                                  fromView:repsStepper.superview];

  CGPoint minusButton = stepperCenter;
  minusButton.x -= CGRectGetWidth(repsStepper.frame) / 4;

  CGPoint plusButton = stepperCenter;
  plusButton.x += CGRectGetWidth(repsStepper.frame) / 4;

  // 2
  [tester waitForTimeInterval:1];

  // 3
  for (int i = 0; i < 20; i++) {
    [tester tapScreenAtPoint:minusButton];
  }

  [tester waitForTimeInterval:1];
  [tester tapScreenAtPoint:plusButton];
  [tester waitForTimeInterval:1];
  [tester tapScreenAtPoint:plusButton];
  [tester waitForTimeInterval:1];

  // 4
  [KIFUITestActor setDefaultTimeout:60];

  // 5
  [tester tapViewWithAccessibilityLabel:@"Start Working"];
  // the timer is ticking away in the modal view...
  [tester waitForViewWithAccessibilityLabel:@"Start Working"];

  // 6
  [KIFUITestActor setDefaultTimeout:10]

这里介绍在最后阶段中即将会发生什么:

  1. 上面的代码寻找UIStepper的加号和减号按钮的坐标。
  2. waitForTimeInterval:调用增加了延时,这样你可以看到步数值的变化——否则的话,对于肉眼而言,它的变化太快了。
  3. 这个步数的最大值是20,所以触击减号按钮20次会把值恢复到1。然后触击加号按钮2次(以最小的延时交替)把重复数字变为期望的值 3。
  4. 每个测试步骤默认的超时时间是10秒。即使在加速调试模式下,有可能20多分钟长度的“工作”也需要超过10秒钟时间完成,所以需要设置一个比较宽松的超时时间——60秒。
  5. 触击“开始工作”按钮,它会弹出模式视图控制器。当重复都结束后,模式视图控制器会消失。这意味着你将返回定时器视图控制器上,所以 等待“开始工作”按钮再次出现其实是在等待模式视图控制器消失。
  6. 重设超时时间为10秒。

一旦你保存文件,你会发现有方法声明一侧会出现一个小的棱形图标:

《使用KIF 进行 iOS UI 测试》

这是一个运行单个测试的按钮。因此,你可以在测试环境下只运行这个方法,而不需要运行整套测试用例。优雅!点击菱形按钮来运行这个测试,你会看到模拟器启动,并运行测试用例。只要坐在一旁观看它输入任务名,滑动滚动条,以及定时器的时间流动就可以了。不用动一根手指,你就能测试UI了。

成功了!现在你可以成功设置测试,帮助你完成一系列UI控制器的操作。

如果你通过菱形按钮跑单个测试,它只跑一个简单的方法而不会在开头调用beforeAll。如果你的测试是依赖于beforeAll的,你仍然需要跑整套完整的测试。

提前结束

“去工作!”模式视图控制器中有一个放弃按钮可以让用户取消一个时间周期。你仍可以测量已经工作的分钟,即使很早就结束了测试。这个数据仍然会被记录到历史上,但会被标记为整个周期没有跑完。

你不用相信我的话,可以自己尝试一下。只需做一些类似上述测试的东西。设置定时器的参数,触击*开始工作按钮,然后触击放弃按钮。

不要马上触击“放弃”按钮——定时器需要运作一段时间,应用程序才开始创建历史记录。所以,你可以将鼠标移动到测试上,手动停止测试。或者,你可以编程设定它在你选定的时间和位置。如果你生性犹豫,你可以跳过这个挑战。然而,如果你喜欢编写应用去帮你处理各种杂事,就试一下吧!你知道如何在“开始工作”和“放弃工作”之间增加一点延时么?

你可以调用waitForTimeInterval:在你的测试里增加延时。

UITests.m中添加下列的测试方法,加在其他测试的下面:

- (void)test30StartTimerAndGiveUp {
  [tester tapViewWithAccessibilityLabel:@"Timer"];

  [tester clearTextFromAndThenEnterText:@"Give Up"
         intoViewWithAccessibilityLabel:@"Task Name"];
  [tester tapViewWithAccessibilityLabel:@"done"];
  [self selectPresetAtIndex:2];

  [tester tapViewWithAccessibilityLabel:@"Start Working"];
  [tester waitForTimeInterval:3];

  [tester tapViewWithAccessibilityLabel:@"Give Up"];
  [[tester usingTimeout:1] waitForViewWithAccessibilityLabel:@"Start Working"];
}

在确保你位于正确的选项卡之后,设置任务名然后选择好预设。然后启动定时器,在放弃之前等待3秒。

方法的最后一行等待模式视图控制器消失,返回主界面。记住,默认的超时时间是10秒,但是实际上不需要这么长时间——触击“放弃”按钮,模式视图控制器会立即消失。

在之前的测试中,你使用了类方法setDefaultTimeout:为所有测试操作设置全局的超时时间。在这里,你可以调用usingTimeout:为某一步定制的超时时间。

保存文件并点击菱形按钮运行单个测试。当定时器开始的时候,你可以发现它在放弃、返回主界面之前会等待3秒。

《使用KIF 进行 iOS UI 测试》

历史和拖动

之前我们没有怎么关注历史选项卡,现在该轮到它出一下风头了。如果你按照练习一步一步来进行操作的话,那么你至少会有一条历史记录。构建并运行该应用,然后切换到历史选项卡。

《使用KIF 进行 iOS UI 测试》

历史表视图实现了最新的iOS7删除手势——当你把整行往左边拖动,然后触击出现的“删除”按钮。这是你的下一个测试!这要求历史中至少有一条记录,所以你跑单个测试的时候要小心。你必须保证历史记录中有内容,否则就没什么可以测的!安全起见,你需要完整地运行整套测试,因为前面的测试会创建一些历史记录供你使用。记住,测试的运行顺序是根据字母顺序排列的,所以你可以很放心,前面的测试会创建一些历史记录的。

如果你看一下HistoryViewController.m中的tableView:cellForRowAtIndexPath:,你会发现每一格都能得到一个辅助标签,比如“第3行第0个”之类的。这有助于KIF找到这一行。但在真实环境下这种标签很糟,所以不要在真正的应用中使用。在示例工程中,我们使用#ifdef来确保这些只出现在调试构建中。你应该在你自己的应用中做类似的事情。请确保在发布构建的时候,将辅助标签设为一些有用的内容,切实为用户提供辅助功能。

现在,打开UITests.m并添加如下的测试方法:

- (void)test30StartTimerAndGiveUp {
  [tester tapViewWithAccessibilityLabel:@"Timer"];

  [tester clearTextFromAndThenEnterText:@"Give Up"
         intoViewWithAccessibilityLabel:@"Task Name"];
  [tester tapViewWithAccessibilityLabel:@"done"];
  [self selectPresetAtIndex:2];

  [tester tapViewWithAccessibilityLabel:@"Start Working"];
  [tester waitForTimeInterval:3];

  [tester tapViewWithAccessibilityLabel:@"Give Up"];
  [[tester usingTimeout:1] waitForViewWithAccessibilityLabel:@"Start Working"];
}

现在介绍上面方法的作用:

  1. 切换到“历史”选项卡。
  2. 引用表视图并追踪总共存在多少行。如果一行数据有没有,测试就会失败。
  3. 往左拖动表视图的单元格。当删除按钮出现后,触击它。
  4. 删除一个单元格的时候,表视图会有一个动画效果,所以在进行下一步前添加一个短暂的延时。再次检查表视图的行数,应当比之前的行数少一行。

用Command-U运行整套测试,所有的测试会顺序执行。

《使用KIF 进行 iOS UI 测试》

现在,你的测试覆盖了整个应用的基本流程了——从数据重置到多次运行定时器,再到验证和删除历史记录。

如果你要继续开发这个应用程序,这些测试会是一个很好的基础,确保界面没有退步。这意味着在主界面变化的时候你需要更新你的测试——测试就像是你应用的规格说明,需要及时更新才能发挥作用。

进一步

到目前为止,你应该对KIF的可能性有很好的了解,脑子里也应该有不少主意,如何利用这个高效的功能测试工具来测试你自己的应用程序。添加KIF到你自己的项目的时候,你可以查看这个文档。你可以手动添加KIF或者使用非常方便的CocoaPods依赖管理。

KIF是一个开源项目,且有许多新功能还在不断开发之中。例如,在写这篇教程的时候,下一个KIF的发布版将会包含截屏的功能。这意味着可以在跑测试的时候通过屏幕截图来查看全过程中的关键点。听起来这不是比用肉眼观察KIF点击和拖动整个过程好上千万倍么?KIF正变得越来越好了,所以学习如何使用它,是一个很好的自我投资。

最后,由于KIF测试用例是OCUnit的子类,并在标准的Xcode5测试框架下运行,你可以使用持续集成来跑这些测试。当你干别的事情的时候,你拥有了一个能够像人的手指一样触控的机器人去测试你的应用程序。太棒了!

你可以在这里下载整个示例项目的代码。测试快乐!

原文 iOS UI Testing with KIF
翻译 SegmentFault

    原文作者:weakish
    原文地址: https://segmentfault.com/a/1190000000447832
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞