单元测试和太空救援任务

我看到无数人鼓吹说单元测试对任何软件项目都非常重要。 实际上,只有极少数人使用令人信服的示例来支持自己的论点,这使得单元测试看起来像是可悲的旧式教条,可以放心地忽略。 人们是榜样的创造者,直到看到一个榜样,我们才会真正相信某些东西。

今天,我再次提出这个论点:单元测试对于确保代码按预期工作至关重要。 单元测试似乎没什么用,因为在您第一次编写代码时,它确实不是很有用。 但是我们不是生活在一个静止的世界中,我们生活在一个市场中,业务逻辑可以在几个小时内多次变化,我们生活在一个明天我们可以与今天的朋友展开战争的世界中。 不断变化的环境意味着不断发展的代码库。 几乎可以肯定,您会回到软件的一部分并对其进行修改,以执行一些不同的操作,尽管有些不同。 更改发生时,单元测试确实会发光:当新更改意外破坏应用程序的其他部分时,它将通知您。

为了支持我的观点,我邀请您进行一次遥远的冒险。

2148年,整个地球都震惊了一个令人震惊的消息:火星人的住所已被我们致命的太空敌人-虫族(Zerg)接管。 我们所有的火星定居者都被劫为人质。

太空级武器制造商Space Force的CTO感到恐惧和愤怒,决定部署一支由您最先进的外星战斗机器人组成的机队,这是世界上最史诗般的太空救援任务之一。

您迅速地慢跑到计算机上,开始键入一个程序,凶猛的机器人机群将在该程序上运行。 您选择了一个多世纪以前开源的编程语言。

当您的机器人到达时,火星将有两种:人类和虫族。 因此,您需要两个模型来表示它们。 由于它们都是有机的,因此您将创建两个符合相同Bio协议的结构。

Bio协议规定,任何Bio单元都将具有两个共同的属性:它们将具有一定数量的腿和体温(以摄氏度为单位)。 根据一直研究这种残酷外来物种的贵公司精英科学家的说法,每个异虫都有8条腿,它们的体温为27摄氏度。

 协议Bio { 
var bodyTemperature:Double {get}
var numberOfLegs:Int {get}
}
  struct Human:Bio { 
让bodyTemperature = 37.0
让numberOfLegs = 2
}
  struct Zerg:Bio { 
让bodyTemperature = 27.0
让numberOfLegs = 8
}

现在,您已经定义了所需的模型,接下来继续向复杂的Zerg杀人机中添加一些代码。

根据您从科学人员那里获得的数据,您可以自信地编写机器人的逻辑代码。 机器人上的高级计算机视觉算法和热传感器可以轻松识别生物的腿数和体温。 因此,您继续创建基于这些属性来确定生物是朋友还是敌人的方法。 在这种方法中,您需要检查以下内容:如果一个生物单元的两条腿以上或它的体温低于30摄氏度,那么消除这种恶心的异虫。

  struct RescueRobot { 
func isTarget(bio:Bio)-> Bool {
返回bio.numberOfLegs> 2 || 生物体温度<30
}

func meetBioBioTarget(bio:Bio){
返回isTarget(bio)吗? 杀死(生物):营救(生物)
}

func kill(bio:Bio){
//释放可怕的武器……代码已被省略。
}

功能救援(bio:Bio){
//做点漂亮的事情……代码也被省略了。
}
}

急着您,不相信进行单元测试的重要性的您,已经准备好将您的机器人运送到火星并节省时间。

搭载机器人的太空船发射前5分钟。 您的科学人员接到了紧急电话。 她告诉您测量已关闭,而Zerg的体温实际上比他们想象的要高。 原来是27摄氏度,而不是27摄氏度。 “轻松解决”,您平静地说。

您打开了编辑器,并进行了一些专业的快速更改:

  func isTarget(bio:Bio)-> Bool { 
返回bio.numberOfLegs> 2 || 生物体温度<40
}

重新启动所有机器人后,它们连同整个星球的希望一起被送入太空。

我身体不好

您的机器人摧毁了整个星球。 他们按照指示消灭了所有的虫族,但没有救出一个人,因为人也被您的冷血机器残酷地杀了。 怎么会这样?

如果您已进行单元测试,则完全可以避免这种悲剧。

假设您进行了两次单元测试,以验证机器人会杀死Zerg但不会杀死人类。

  func testIsTargetWhenEncounterHuman(){ 
让人类=人类()
XCTAssertFalse(rescueRobot.isTarget(human),“人类不应成为目标”)
}

func testIsTargetWhenEncounterZerg(){
让zerg = Zerg()
XCTAssertTrue(rescueRobot.isTarget(zerg),“ Zerg应该是目标”)
}

“ testIsTargetWhenEncounterHuman”在修改之前通过,但在修改之后将失败。

如您所见,现实世界中不断变化的环境通常会迫使您以多种方式修改逻辑。 通过进行单元测试来验证您软件的预期行为,可以节省您的时间,麻烦和生命。 在您的第一次迭代中,它似乎不太有用,但是只要您回到代码库,它就可以提供必要的健全性检查和无比的信心。