A4ba261fa86ab3ca4563351001ee56c7
WWDC20 10091 - 编写会“失败”的测试

这个 session 的标题很有意思,编写会“失败”的测试。一般情况下,工程师都希望写完测试代码,一路“绿灯”全部通过,然后窃喜于自己写的代码多么牛逼。但是真正好的测试代码反而是能够抓住潜在 bug 的测试代码,也就是会让测试“失败”的代码。请注意这个 session 的内容主要是讲 UI 测试,但是同样适用于单元测试。

测试用例可以是在本地 Xcode 跑,也可以在 CI 机器上跑。 如果在 CI 上跑的话,测试结果会在 result bundle 里面,然后我们可以根据 test bundle 打印的信息分析测试结果。好的测试代码,应该能帮助快读定位问题,而且更加健壮,这个 session 会告诉大家如何做到以上这两点。我们知道,测试一般分为三个步骤,set up, test, tear down。其中第二步 test 又可以分为两个子步骤,行为(actions)和断言(assertions),这个 session 就是以此为框架具体阐述如何编写好的测试代码。

先谈第一步 Set up

Xcode 11.4 增加了一个新的 API setUpWithError() throws。建议之前用 setUp() 的同学都迁移到这个新的 API,如果 setUp 过程发生错误,这个 API 可以抛出异常并提前终止测试。

在这个方法里一般需要重置 APP 状态,比如上次测试权限打开了应用权限,这里可以 reset 应用权限。一般建议设置continueAfterFailure = false, 这样在失败后立即停止继续测试,确保遇到第一个错误后立即停止,避免多个错误混在一起对排查问题造成困难。最后这个方法需要运行 app.launch() 启动 APP,启动 APP 之前也可以添加启动参数或者环境变量,例如app.launchArguments.append("-recipes-tests")。加启动参数或者环境变量的主要目的是加速你的测试过程,比如你需要跳过两步验证,又或者你的 APP 有四个 tab,而你需要直接跳到第四个tab进行相关场景测试。这样可以快速到达你的测试场景,也可以避免在其他前置场景就已经测试失败影响你的测试。

第二步 Test

测试无非就是触发某个行为,并通过断言判断这个行为带来预期的结果。

行为(Actions)

测试方法的命名很重要,一般你要想好你的测试目标是什么,然后就用这个目的来命名。比如你是要测试一个食谱 APP 里面的 Ingredients 列表的正确性,那么你可以将测试方法命名为 testIngredientsListAccuracy。下面是这个测试方法的具体内容,即测试 APP 里面的一个奶昔列表,选中一个品类,就可以看到这个品类对应的原料详情页。

在实际编写测试行为代码的过程中,总结下来有下面的小技巧:

  1. 同一个 UI 的名字经常变怎么办?可以用 enum 来解决,把字符串转成 enum 的形式来表达,这样如果 Label 的名字变了,只需要把 enum 对应的 string 值直接修改即可。
  2. 把多个测试中出现的重复代码包装成 helper function。
  3. 用面向对象的方法去组织测试代码,把测试代码写成易读的形式,比如app.smoothieList().select(smoothie: .berryblue)一眼就能看出是想要做的事情是从列表中点击一个元素。
  4. 随着测试代码越来越庞大,可以把一些测试代码用产品代码一样的方式管理起来,比如包装成 framework 或者是 Swift package,这样可以在多个项目之间共享测试代码。
top Created with Sketch.