返回介绍

建议75:利用测试驱动开发提高代码的可测性

发布于 2024-01-30 22:19:09 字数 2723 浏览 0 评论 0 收藏 0

测试驱动开发(Test Driven Development,TDD)是敏捷开发中一个非常重要的理念,它提倡在真正开始编码之前测试先行,先编写测试代码,再在其基础上通过基本迭代完成编码,并不断完善。其目的是编写可用的干净的代码。所谓可用就是能够通过测试满足基本功能需求,而干净则要求代码设计良好、可读性强、没有冗余。在软件开发的过程中引入TDD能带来一系列好处,如改进的设计、可测性的增强、更松的耦合度、更强的质量信心、更低的缺陷修复代价等。那么,如何在编程过程中实施测试驱动开发呢?一般来说,遵循如图7-2所示的过程。

图7-2 测试驱动开发流程

1)编写部分测试用例,并运行测试。

2)如果测试通过,则回到测试用例编写的步骤,继续添加新的测试用例。

3)如果测试失败,则修改代码直到通过测试。

4)当所有测试用例编写完成并通过测试之后,再来考虑对代码进行重构。

假设开发人员需要编写一个求输入数列的平均数的例子。在开始编写测试用例之前我们先编写简单的编码以保证测试能真正开始执行。

假设源文件avg.py内容如下:

def avg(x):
  pass

当完成基本的代码框架之后,便可以开始实施TDD的具体过程了。

步骤1 编写测试用例。基本的测试用例应该包括对整数、浮点数、混合输入情况下基本功能的验证,以及对空输入、无效输入的处理。测试用例代码如下:

import unittest
from avg import avg
class TestAvg(unittest.TestCase):
   def test_int(self):
       print "test average of integers:"
       self.assertEqual(avg([0,1,2]),1)
   def test_float(self):
       print "test average of float:"
       self.assertEqual(avg([1.2,2.5,0.8]),1.5)
   def test_empty(self):
       print "test empty input:"
       self.assertFalse(avg([]),False)
   def test_mix(self):
       print "test with mix input:"
       self.assertEqual(avg([-1,3,7]),3)
   def test_invalid(self):
       print "test with  invalid input:"
       self.assertRaises(TypeError,avg,[-1,3,[1,2,3]])
if __name__ == '__main__':
   unittest.main()

步骤2 运行测试用例(部分输出),测试结果显示失败,如图7-3所示。

图7-3 测试结果

步骤3 开始编码直到所有的测试用例都通过。这是一个不停地重复迭代的过程,需要多次重复编码测试,直到上面的测试用例全部执行成功。

def avg(x):
   if len(x)<=0:
      print "you need input at least one number"
      return False
   sum = 0
   try:
      for i in x:
        sum += i
   except TypeError:
       raise TypeError("your input is not value with unsupported type")
   return sum/len(x)

步骤4 重构。在测试用例通过测试之后,现在可以考虑一下重构的问题了。代码有没有更优化的实现方式呢?显然直接利用内建函数sum更高效直接。因此对代码进行重构并重新测试生成最终产品代码。

def avg(*x):
   if len(*x)<=0:
      print "you need input at least one number"
      return False
   try:
      return sum(*x)/len(*x)
   except TypeError:
      raise TypeError("your input is not value with unsupported type")

关于测试驱动开发和提高代码可测性方面有以下几点需要说明:

TDD只是手段而不是目的,因此在实践中尽量只验证正确的事情,并且每次仅仅验证一件事。当遇到问题时不要局限于TDD本身所涉及的一些概念,而应该回头想想采用TDD原本的出发点和目的是什么。

测试驱动开发本身就是一门学问,不要指望通过一个简单的例子就掌握其精髓。如果需要更深入的了解,推荐在阅读相关书籍的同时在实践中不断提高对其的领悟。

代码的不可测性可以从以下几个方面考量:实践TDD困难;外部依赖太多;需要写很多模拟代码才能完成测试;职责太多导致功能模糊;内部状态过多且没有办法去操作和维护这些状态;函数没有明显返回或者参数过多;低内聚高耦合;等等。如果在测试过程中遇到这些问题,应该停下来想想有没有更好的设计。

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文