Logo
Section 1 / 7

(不)深入其中

通过测试驱动开发用 unittest 编写罗马数字转换的单元测试

导入

(不)深入其中

通过测试驱动开发用 unittest 编写罗马数字转换的单元测试

如今的孩子们。被这些快速的计算机和花哨的“动态”语言宠坏了。先写代码,再发布,调试则能省则省(甚至可能根本不去调试)。在我那个年代,我们可是有纪律的!纪律,我说!我们必须亲手在纸上编写程序,然后通过打孔卡把它们输入计算机。而且我们还乐在其中!

在本章中,你将编写并调试一组实用函数,用于在罗马数字与普通数字之间进行转换。你在“案例研究:罗马数字”中已经了解了构造和验证罗马数字的基本原理。现在,请退后一步,思考一下如何将这些功能扩展为一个双向转换工具。

罗马数字的规则带来了一些有趣的观察:

  1. 每个数字只有一种正确的罗马数字表示方式。
  2. 反过来也成立:如果一段字符是有效的罗马数字,它只能对应一个唯一的数值(即只有一种解释方式)。
  3. 罗马数字能表示的范围有限,具体为 1 到 3999。虽然古罗马人曾用一些方法表示更大的数,比如在数字上方加横线表示其值乘以 1000,但本章中我们规定罗马数字仅限于 1 到 3999。
  4. 罗马数字无法表示 0。
  5. 罗马数字无法表示负数。
  6. 罗马数字无法表示分数或非整数。

让我们开始规划 roman.py 模块应该实现的功能。它将包含两个主要函数:to_roman() 和 from_roman()。to_roman() 函数应接收一个介于 1 到 3999 之间的整数,并返回对应的罗马数字字符串……

停一下。现在来点出人意料的事:写一个测试用例,检查 to_roman() 函数是否符合你的预期。你没看错:你要写一段代码来测试一段尚未编写的代码。

这被称为测试驱动开发(Test-Driven Development,简称 TDD)。这两个转换函数——to_roman() 和稍后加入的 from_roman()——可以作为一个独立单元进行编写和测试,而无需依赖任何导入它们的大型程序。Python 提供了一个单元测试框架,名为 unittest 模块。

单元测试是整体以测试为中心的开发策略中的重要组成部分。如果你编写单元测试,那么尽早编写并随着代码和需求的变化持续更新它们非常重要。许多人主张在编写被测代码之前先写测试,这也是本章将展示的风格。但无论何时编写单元测试,它们都有显著的好处:

  • 在编写代码之前编写单元测试,能迫使你以一种有用的方式详细说明需求。
  • 在编写代码的过程中,单元测试能防止你过度编码。当所有测试用例都通过时,函数就完成了。
  • 在重构代码时,它们可以帮助证明新版本的行为与旧版本一致。
  • 在维护代码时,测试能帮你应对他人指责你修改破坏了原有功能的情况。(“可是先生,我提交前所有单元测试都通过了……”)
  • 在团队协作中,拥有全面的测试套件能极大降低你的代码破坏他人代码的可能性,因为你可以在集成前先运行他们的单元测试。(我曾在代码冲刺中见过这种情况:团队分工后,每个人拿到自己的任务说明,先编写对应的单元测试,再与其他成员共享测试用例。这样就能确保大家不会各自开发出彼此不兼容的代码。)

高级迭代器

一个单一问题