深入Python3(九) 重构 您所在的位置:网站首页 python重构 深入Python3(九) 重构

深入Python3(九) 重构

2024-04-01 18:02| 来源: 网络整理| 查看: 265

文章目录 0.摘要1.新的错误2.控制需求变化3.重构4.总结

0.摘要

  本章继续深入前一章节的例子,通过更改需求—修改代码—重构这一流程让你逐步意识到单元测试的意义,以及它对重构的重要性。

1.新的错误

  就算是竭尽了全力编写全面的单元测试,还是会遇到错误。我所说的“错误”是什么意思?错误是尚未写到的测试实例。 在这里插入图片描述 在这里插入图片描述

   这段代码非常简单。通过传入一个空字符串调用 f r o m _ r o m a n ( ) from\_roman() from_roman() ,并确保其引发一个 I n v a l i d R o m a n N u m e r a l E r r o r InvalidRomanNumeralError InvalidRomanNumeralError 例外。难的是发现错误;找到了该错误之后对它进行测试是件轻松的工作。 在这里插入图片描述 在这里插入图片描述 在这里插入图片描述

  用此方式编写代码将使得错误修正变得更困难。简单的错误(像这个)需要简单的测试实例;复杂的错误将会需要复杂的测试实例。在以测试为中心的环境中,由于必须在代码中精确地描述错误(编写测试实例),然后修正错误本身,看起来好像修正错误需要更多的时间。而如果测试实例无法正确地通过,则又需要找出到底是修正方案有错误,还数测试实例本身就有错误。然而从长远看,这种在测试代码和经测试代码之间的来回折腾是值得的,因为这样才更有可能在第一时间修正错误。同时,由于可以对新代码轻松地重新运行 所有 测试实例,在修正新代码时破坏旧代码的机会更低。今天的单元测试就是明天的回归测试。

2.控制需求变化

  为了获取准确的需求,尽管已经竭力将客户“钉”在原地,并经历了反复剪切、粘贴的痛苦,但需求仍然会变化。大多数客户在看到产品之前不知道自己想要什么,而且就算知道,他们也不擅长清晰地表述自己的想法。而即便擅长表述,他们在下一个版本中也会提出更多要求。因此,必须随时准备好更新测试实例以应对需求变化。   举个例子来说,假定我们要扩展罗马数字转换函数的能力范围。正常情况下,罗马数字中的任何一个字符在同一行中不得重复出现三次以上。但罗马人却愿意该规则有个例外:通过一行中的 4 个 M 字符来代表 4000 。进行该修改后,将会把可转换数字的范围从 1…3999 拓展为 1…4999。但首先必须对测试实例进行一些修改。 在这里插入图片描述 在这里插入图片描述

  现有的已知数值不会变(它们依然是合理的测试数值),但必须在 4000 范围之内(外)增加一些。在此,我已经添加了 4000 (最短)、 4500 (第二短)、 4888 (最长) 和 4999 (最大)。   “过大值输入” 的定义已经发生了变化。该测试用于通过传入 4000 调用 to_roman() 并期望引发一个错误;目前 4000-4999 是有效的值,必须将该值调整为 5000 。   “太多重复数字”的定义也发生了变化。该测试通过传入 ‘MMMM’ 调用 from_roman() 并预期发生一个错误;目前 MMMM 被认定为有效的罗马数字,必须将该条件修改为 ‘MMMMM’ 。   对范围内的每个数字进行完整循环测试,从 1 到 3999。由于范围已经进行了拓展,该 for 循环同样需要修改为以 4999 为上限。 在这里插入图片描述 在这里插入图片描述 在这里插入图片描述

  现在,我们有了一些由新需求导致失败的测试实例,可以考虑修正代码让它与新测试实例一致起来(刚开始编写单元测试的时候,被测试代码绝不会在测试实例“之前”出现确实让人感觉有点怪)。尽管编码工作被置后安排,但还是不少要做的事情,一旦与测试实例相符,编码工作就可以结束了。一旦习惯单元测试后,您可能会对自己曾在编程时不进行测试感到很奇怪。 在这里插入图片描述 在这里插入图片描述

3.重构

  关于全面单元测试,最美妙的事情不是在所有的测试实例通过后的那份心情,也不是别人抱怨你破坏了代码,而你通过实践证明自己没有时的快感。单元测试最美妙之处在于它给了你大刀阔斧进行重构的自由。   重构是修改可运作代码,使其表现更佳的过程。通常,“更佳”指的是“更快”,但它也可能指的是“占用更少内存“、”占用更少磁盘空间“或者”更加简洁”。对于你的环境、你的项目来说,无论重构意味着什么,它对程序的长期健康都至关重要。   本例中,“更佳”的意思既包括“更快”也包括“更易于维护”。具体而言,因为用于验证罗马数字的正则表达式生涩冗长,该 f r o m _ r o m a n ( ) from\_roman() from_roman() 函数比我所希望的更慢,也更加复杂。现在,你可能会想,“当然,正则表达式就又臭又长的,难道我有其它办法验证任意字符串是否为罗马数字吗?”   答案是:只针对 5000 个数进行转换;为什么不知建立一个查询表呢?意识到 根本不需要使用正则表达式 之后,这个主意甚至变得更加理想了。在建立将整数转换为罗马数字的查询表的同时,还可以建立将罗马数字转换为整数的逆向查询表。在需要检查任意字符串是否是有效罗马数字的时候,你将收集到所有有效的罗马数字。“验证”工作简化为一个简单的字典查询。   最棒的是,你已经有了一整套单元测试。可以修改模块中一半以上的代码,而单元测试将会保持不变。这意味着可以向你和其他人证明:新代码运作和最初的一样好。 在这里插入图片描述 在这里插入图片描述 在这里插入图片描述

  可以注意到这是一次函数调用,但没有 i f if if 语句包裹住它。这不是 i f   _ _ n a m e _ _   = = ′ _ _ m a i n _ _ ′ if\ \_\_name\_\_\ == '\_\_main\_\_' if __name__ ==′__main__′ 语块;模块被导入时它将会被调用(重要的是必须明白:模块将只被导入一次,随后被缓存了。如果导入一个已导入模块,将不会导致任何事情发生。因此这段代码将只在第一次导入时运行)。 在这里插入图片描述

  这是一段聪明的程序代码……也许过于聪明了。上面定义了 t o _ r o m a n ( ) to\_roman() to_roman() 函数;它在查询表中查找值并返回结果。而 b u i l d _ l o o k u p _ t a b l e s ( ) build\_lookup\_tables() build_lookup_tables() 函数重定义了 t o _ r o m a n ( ) to\_roman() to_roman() 函数用于实际操作(像添加查询表之前的例子一样)。在 b u i l d _ l o o k u p _ t a b l e s ( ) build\_lookup\_tables() build_lookup_tables() 函数内部,对 t o _ r o m a n ( ) to\_roman() to_roman() 的调用将会针对该重定义的版本。一旦 b u i l d _ l o o k u p _ t a b l e s ( ) build\_lookup\_tables() build_lookup_tables() 函数退出,重定义的版本将会消失 — 它的定义只在 b u i l d _ l o o k u p _ t a b l e s ( ) build\_lookup\_tables() build_lookup_tables() 函数的作用域内生效。 在这里插入图片描述

  像前面那样进行同样的边界检查之后, t o _ r o m a n ( ) to\_roman() to_roman() 函数只需在查询表中查找并返回适当的值。   同样, f r o m _ r o m a n ( ) from\_roman() from_roman() 函数也缩水为一些边界检查和一行代码。不再有正则表达式。不再有循环。 在这里插入图片描述

  它不仅能够回答你的问题,还运行得非常快!好象速度提升了 10 倍。当然,这种比较并不公平,因为此版本在导入时耗时更长(在建造查询表时)。但由于只进行一次导入,启动的成本可以由对 t o _ r o m a n ( ) to\_roman() to_roman() 和 f r o m _ r o m a n ( ) from\_roman() from_roman() 函数的所有调用摊薄。由于该测试进行几千次函数调用(来回单独测试上万次),节省出来的效率成本得以迅速提升! 在这里插入图片描述

  在学完这一章后我也稍微认识到了单元测试的重要性……确实如果没有足够的测试用例的话,对代码重构是一件很头疼的事情,我会非常纠结新代码和旧代码的功能是否一致……这甚至会影响重构代码的效率。然而在拥有完备的单元测试的情况下,你可以放心的去重构代码,因为可以迅速的检验新旧代码功能的一致性。

4.总结

  单元测试是一个威力强大的概念,如果正确实施,不但可以降低维护成本,还可以提高长期项目的灵活性。但同时还必须明白:单元测试既不是灵丹妙药,也不是解决问题的魔术,更不是银弹。编写良好的测试实例非常艰难,确保它们时刻保持最新必须成为一项纪律(特别在客户要求关键错误修正时)。单元测试不是功能测试、集成测试或用户承受能力测试等其它测试的替代品。但它是可行的、行之有效的,见识过其功用后,你将对之前曾没有用它而感到奇怪。 在这里插入图片描述



【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有