魏名华

不要偷懒,做更好的自己

Nothing


No Welcome Message

单元测试

单元测试

https://onevcat.com/2014/05/kiwi-mock-stub-test/ http://www.jianshu.com/p/b549fadc0f0c http://blog.csdn.net/hello_hwc/article/details/60957515

单元测试之前

对于iOS开发来说,良好的代码设计,是实行单元测试的前提。是吗???

WWDC中的视频和demo

engineering_for_testability,很有启发。

objc.io 的三篇文章:

更轻量的 View Controllers

  1. 把 Data Source 和其他 Protocols 分离出来。比如:UITableViewDataSource抽出来,代码移到单独的类ArrayDataSource。
  2. 将业务逻辑移到 Model 中。比如一些数据的处理。
  3. 有些代码不能被轻松地移动到 model 对象中,创建单独的类。
  4. 不要在 view controller 中做网络请求的逻辑。
  5. 把 View 代码移到 View 层,即通过封装新的view实现,而不是代码全写在ViewController。

整洁的 Table View 代码

  1. 将UITableViewController作为 child view controller 添加到其他 view controller 中,感觉不会好用。
  2. 分离关注点:

    2.1. 通过cell的category来装配数据;

    2.2. 多种 model 对象需要用同一类型的 cell 来表示,让 Cells 可复用,即给 cell 定义一个 protocol,需要用这个 cell 显示的对象必须遵循这个 protocol。然后简单修改 category 中的设置方法,让它可以接受遵循这个 protocol 的任何对象。这些简单的步骤让 cell 和任何特殊的 model 对象之间得以解耦,让它可适应不同的数据类型;

    2.3. 在 Cell 内部控制 Cell 的状态,比如高亮;

  3. 控制多个 Cell 类型,在 Data Source 做分发;
  4. 编辑 Table View,修改数据很明显是属于 model 层的任务。Model 应该为诸如删除或重新排序等操作暴露一个 API,然后我们可以在 data source 方法中调用它。

测试 View Controllers

  1. 查看代码,里面演示了如何测试Model,DataSource,ViewController。

MOCK & STUB

14年,在objc中,现在比较流行的BDD框架有cedar,specta和Kiwi。 现在,Quick的star数是7000多

BDD: 一个典型的BDD的测试用例包活完整的三段式上下文,测试大多可以翻译为Given..When..Then的格式

STUB: 我们人为地来指定计算的结果,然后测试数据库的写入操作。人为地让一个对象对某个方法返回我们事先规定好的值,这就叫做 stub

MOCK: mock 其实就是一个对象,它是对现有类的行为一种模拟(或是对现有接口实现的模拟), mockstub 最大的区别在于 stub 只是简单的方法替换,而不涉及新的对象,被 stub 的对象可以是业务代码中真正的对象。而 mock 行为本身产生新的(不可能在业务代码中出现的)对象,并遵循类的定义相应某些方法

Quick

// Swift

import Quick
import Nimble

class TableOfContentsSpec: QuickSpec {
  override func spec() {
    describe("the 'Documentation' directory") {
      it("has everything you need to get started") {
        let sections = Directory("Documentation").sections
        expect(sections).to(contain("Organized Tests with Quick Examples and Example Groups"))
        expect(sections).to(contain("Installing Quick"))
      }

      context("if it doesn't have what you're looking for") {
        it("needs to be updated") {
          let you = You(awesome: true)
          expect{you.submittedAnIssue}.toEventually(beTruthy())
        }
      }
    }
  }
}

参考Quick的中文文档,知识点太多了主要有

使用明确清晰的方法名字

-func testPeel() { +func testPeel_makesTheBananaEdible() {

Arrange, Act, and Assert 三部曲

Arrange - 安排好所有先要条件和输入 Act - 对要测试的对象或方法进行演绎 Assert - 作出预测结果的断言

对条件进行测试

每个条件都进行测试

用 XCTestCase.setUp() 来编写更简洁的 “Arrange”

别测试代码,而应该验证程序的行为

比如测试数据库保存操作,不应该存储之后检查记录数是否加1,而应该检查存储后能否顺利取出

编写行为测试的关键,就在于思考这些问题:

这段程序代码是用来做什么的? 我的测试只验证了程序的行为吗?它可能因为代码运行的其他原因而不通过吗?

如何触发 UIViewController 生命周期事件,如何触发 UIControl 事件(如:点击按钮)

Quick 使用mock

Quick 使用 Shared Assertion 来复用测试模板代码

在某种场合下,一些特定的测试代码可以应用在不同的对象上。

比如,假设有一个叫 Edible 的协议。当一只海豚吃了标识为 Edible 的食物时,它会变得高兴。Mackerel 和 Cod 都遵循 Edible 协议。这个时候,Quick 的 shared example(共享用例)能帮你更容易地测试 Mackerel 和 Cod 的行为。

Quick 使用beforeEach 和 afterEach