专栏首页华仔的技术笔记译:如何用Swift进行TDD(测试驱动开发)

译:如何用Swift进行TDD(测试驱动开发)

如果你还没有用类似Swift的编译型语言进行过TDD,你可能想问:如果测试引用的对象不存在,你怎么进行代码编译,又怎么进行TDD呢?

相对于类似Swift的编译型语言,类似Ruby和JavaScript的解释型语言可能天生更适合TDD,因为你可以编写不存在的测试对象,并且不会产生编译错误。

所以该如何用编译型语言进行TDD?

你可以直接编写测试代码,放任它编译失败。如果你把“编译失败”当作解释型语言的测试失败,就简单多了。失败就是失败,无论是由于编译器还是你的测试。

为了说明这一点,我们对Project类进行TDD,我们希望创建一个它的字典,这样之后可以进行序列化。

1、创建一个测试和你想要存在的实例

因为我们想要测试的是创建一个Project的字典,我们需要一个Project的实例(当前它并不存在)。

class ProjectTests: XCTestCase { func test_asDictionary() { let project = Project(id: 5) } } 编译失败,所以测试失败了。我们有一个好的开始,说真的,这就是TDD——我们希望我们的第一个测试是失败的。

测试状态:红色。

2、编写你想要存在的类

为了解决编译错误,Project需要一个有id参数的init,代码如下:

class Project { private let id: Int

init(id: Int) {
    self.id = id
}

} 这修复了编译错误,所以测试通过。

测试状态:绿色。

3、在测试中,调用你想要存在的方法

现在我们想用Project实例调用asDictionary方法,这个方法将给我们Project的字典表示。

func test_asDictionary() { let project = Project(id: 5) let dict = project.asDictionary() } 编译失败,所以测试状态为红色。好,我们可以继续进行。

测试状态:红色。

4、编写你想要存在的方法

在Project类里,我们现在可以实现asDictionary方法了,但是注意我们要用最简短的代码来通过测试。(换句话说,不要用的id属性!)

func asDictionary() -> [String: AnyObject] { return String: AnyObject } 记住,在TDD过程中,我们总是试图做最简单的事情来通过测试。所以这里我们只返回一个空的字典——我们暂时不需要任何键或值,因为没有失败的测试告诉我们这样做。

这使得测试状态为绿色,因为它修复了编译错误。当然,我们的测试还不告诉我们很多信息,所以我们需要写一个断言。

测试状态:绿色。

5、在测试里,编写一个断言

现在我们可以在asDictionary方法的返回值里做断言。我们希望Project的id出现在字典里。所以我们的测试变成了这样:

func test_asDictionary() { let project = Project(id: 5) let dict = project.asDictionary()

XCTAssertEqual(dict["id"] as? Int, 5)

} 这通过了编译,但是运行的时候,测试失败了,它告诉我们nil并不等于5。我们的测试再次失败,但没关系,我们可以修复它!

测试状态:红色。

6、实现方法,来通过测试

现在我们可以编写方法逻辑,履行断言,使测试通过。

回到我们的Project,我们可以更新asDictionary:

func asDictionary() -> [String: AnyObject] { return ["id": 5] } 什么?你可能会想,现在我们不是应该返回id而不是5吗?如果我们真的在实行TDD,那就不应该,我们不应该返回id属性的值。返回硬编码值5在这里是最简单的通过测试的方法。如果我们想断言返回的字典里有id,我们需要另一个测试。

测试状态:绿色。断言状态:不够好。

7、编写另一个测试,下一个新的断言

现在我们可以编写一个完整的测试,并且没有任何编译错误。我们会创建一个新的测试,其中Project的id能给出除5以外的一个值,调用asDictionary,下断言。

func test_asDictionary_with_id_7() { let project = Project(id: 7) let dict = project.asDictionary()

XCTAssertEqual(dict["id"] as? Int, 7)

} 这将会编译失败,因为asDictionary的id值总是5。这很好,因为现在我们有一些不错的断言告诉我们代码应该如何工作。

测试状态:红色。断言状态:好。

8、实现方法,使测试通过

现在我们可以更新asDictionary使我们的测试通过。但是这一次,返回一个硬编码["id": 7]并没有用,因为这将打破我们的第一个测试。我们可以修改这个方法来返回字典里的id值,像这样:

func asDictionary() -> [String: AnyObject] { return ["id": id] } 当我们运行测试,他们通过了!现在我们可以相信asDictionary将始终返回字典里的id。

测试状态:绿色。断言状态:好。

结论

你可以用类似Swift的编译型语言实践TDD——事实上, Test Driven Development: By Example(这本书继续谈了TDD)使用了Java这个编译型语言来说明如何进行TDD。只要你以同样的方式对待编译错误和解释型语言的测试失败,TDD过程是完全相同的。

http://www.cocoachina.com/swift/20151112/14152.html

翻译:http://roadfiresoftware.com/2015/09/how-you-can-do-tdd-with-swift/

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 一个区块链黑科技开源框架-光子网络(photon network)

    纵所周知,以太坊的雷电网络(i.e Lighting on Ethereum)使用了链下交易的方式来解决目前交易拥堵问题,并实现实时的交易确认。是一种链下规模性...

    rectinajh
  • Ubuntu 上使用mysql一点小经验

    查看表:使用describe 表;查看(注:一定要使用use 表进入数据库之后才能使用这个命令)

    rectinajh
  • Ethereum的理解

    rectinajh
  • Mybatis—查询resultMap-多表关联{association-collection}–延迟加载

    resultMap: 结果映射。 自定义列名和java对象属性的对应关系。 常用在列名和属性名不同的情况。

    Java架构师必看
  • 面试官问:MySQL的自增ID用完了,怎么办?

    可以发现 AUTO_INCREMENT 已经自动变成2,这离用完还有很远,我们可以算下最大当前声明的自增ID最大是多少,由于这里定义的是 intunsigned...

    xcbeyond
  • 面试官问:MySQL的自增ID用完了,怎么办?

    可以发现 AUTO_INCREMENT 已经自动变成2,这离用完还有很远,我们可以算下最大当前声明的自增ID最大是多少,由于这里定义的是 intunsigned...

    田维常
  • 2.MySQL表操作

    表就相当于文件,表中的一条记录就相当于文件的一行内容,不同的是,表中的一条记录有对应的标题,称为表的字段

    changxin7
  • java进阶|MyBatis系列文章(七)多表查询操作

    以上jar包依赖主要是mysql连接,支持mybatis操作以及简化get/set方法的lombok包。

    码农王同学
  • Linux 修改用户组后,如何关闭所有 X session 下使得组生效?

    最近在使用 docker-ce ,在配置当前用户组为 docker 的时候(sudo usermod -aG docker $USER)发现:必须要关闭当前的 ...

    xuyaowen
  • DiscuzX2.5数据库字典

    pre_common_admincp_cmenu – 后台菜单收藏表 title => ‘菜单名称’ url => ‘菜单地址’ sort => ’0′ COM...

    joshua317

扫码关注云+社区

领取腾讯云代金券