【Kickstarter-iOS 源码分析】07 - 测试

417 阅读2分钟
Kickstarter-iOS源码地址 >>

测试,是软件开发中非常重要的一个环节。我翻阅了 Kickstarter-iOS 中的大部分测试文件,这篇文章我来总结一下在 Kickstarter-iOS 中都测试了什么和怎样进行测试的。

单元测试

在 Kickstarter-iOS 中,单元测试的对象主要分两类:Model 和 ViewModel。

Model

在定义一个 Model 时,一般都会实现 Codable,并且要测试一下对于给定的 json 数据,是否可以解析成功。Kickstarter-iOS 也是这么做的:在每一个 Model 对应的测试文件里,利用假的 json 数据,测试是否可以解析成功。

例如 AuthorTests.swift里:

func testJSONParsing_WithCompleteData() {

    let author = Author.decodeJSONDictionary([
      "id": 382491714,
      "name": "Nino Teixeira",
      "avatar": [
        "thumb": "https://ksr-qa-ugc.imgix.net/thumb.jpg",
        "small": "https://ksr-qa-ugc.imgix.net/small.jpg",
        "medium": "https://ksr-qa-ugc.imgix.net/medium.jpg"
      ],
      "urls": [
        "web": [
          "user": "https://staging.kickstarter.com/profile/382491714"
        ],
        "api": [
          "user": "https://api-staging.kickstarter.com/v1/users/382491714"
        ]
      ]
      ])

    XCTAssertNil(author.error)
    XCTAssertEqual(382491714, author.value?.id)
}

除此之外,根据具体的业务,还会有一些其他测试。

ViewModel

在 Kickstarter-iOS 中,每个 ViewModel 都会有对应的测试。这里主要讲一下有哪些小技巧值得学习的。

  1. XCTestCase+AppEnvironment.swift中, 通过扩展 XCTestCase 定义了 withEnvironment() 方法,用于替换某些全局变量,把替换后的 Environment push 到 stack 中作为当前的 Environment,执行完 body()后,再把刚刚 push 的 Environment 移除,这样可以保证不改变测试前后的 Environment。
func withEnvironment(_ env: Environment, body: () -> Void) {
    AppEnvironment.pushEnvironment(env)
    body()
    AppEnvironment.popEnvironment()
}

func withEnvironment(...) # 具体看文件
  1. 基本上每一个 Model 都会定义一个 template 实例,用于在 ViewModel 中测试。

UI 测试

在 Kickstarter-iOS 中,UI 测试主要是对 ViewController 的测试,看看 UI 的显示是否有问题。

因为 Kickstarter 支持多语言,并且 iOS 设备有多种尺寸,所以定义了一个 combos 方法,用于组合各种语言和尺寸:

internal func combos<A, B>(_ xs: [A], _ ys: [B]) -> [(A, B)] {
  return xs.flatMap { x in
    return ys.map { y in
      return (x, y)
    }
  }
}

另外还定义了一个方法,根据设备的大小和朝向最终把传入的 controller 转变成对应设备大小的 controller。

internal func traitControllers(device: Device = .phone4_7inch,
                               orientation: Orientation = .portrait,
                               child: UIViewController = UIViewController(),
                               additionalTraits: UITraitCollection = .init(),
                               handleAppearanceTransition: Bool = true)
  -> (parent: UIViewController, child: UIViewController)

最后再用 FBSnapshotTestCase 生成各种尺寸语言组合的截图,具体代码如下:

func testAddNewCard() {
    combos(Language.allLanguages, Device.allCases).forEach { language, device in
      withEnvironment(language: language) {
        let controller = AddNewCardViewController.instantiate()
        let (parent, _) = traitControllers(device: device, orientation: .portrait, child: controller)

        FBSnapshotVerifyView(parent.view, identifier: "lang_\(language)_device_\(device)")
      }
    }
}

这个测试就会生成以下截图:

总结

这篇文章主要对 Kickstarter-iOS 中测试的主要规律进行了总结。至于具体的测试,还请读者根据需求对具体代码进行分析。

想及时看到我的新文章的,可以关注我。